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 <limits>
38 #include <memory>
39 #include <vector>
40
41 #include <google/protobuf/any.pb.h>
42 #include <google/protobuf/compiler/importer.h>
43 #include <google/protobuf/compiler/parser.h>
44 #include <google/protobuf/unittest.pb.h>
45 #include <google/protobuf/unittest_custom_options.pb.h>
46 #include <google/protobuf/stubs/common.h>
47 #include <google/protobuf/stubs/logging.h>
48 #include <google/protobuf/stubs/stringprintf.h>
49 #include <google/protobuf/unittest_lazy_dependencies.pb.h>
50 #include <google/protobuf/unittest_proto3_arena.pb.h>
51 #include <google/protobuf/io/tokenizer.h>
52 #include <google/protobuf/io/zero_copy_stream_impl.h>
53 #include <google/protobuf/descriptor.pb.h>
54 #include <google/protobuf/descriptor.h>
55 #include <google/protobuf/descriptor_database.h>
56 #include <google/protobuf/dynamic_message.h>
57 #include <google/protobuf/text_format.h>
58 #include <google/protobuf/stubs/strutil.h>
59 #include <gmock/gmock.h>
60 #include <google/protobuf/testing/googletest.h>
61 #include <gtest/gtest.h>
62 #include <google/protobuf/stubs/logging.h>
63 #include <google/protobuf/stubs/substitute.h>
64
65
66 // Must be included last.
67 #include <google/protobuf/port_def.inc>
68
69 using ::testing::AnyOf;
70
71 namespace google {
72 namespace protobuf {
73
74 // Can't use an anonymous namespace here due to brokenness of Tru64 compiler.
75 namespace descriptor_unittest {
76
77 // Some helpers to make assembling descriptors faster.
AddMessage(FileDescriptorProto * file,const std::string & name)78 DescriptorProto* AddMessage(FileDescriptorProto* file,
79 const std::string& name) {
80 DescriptorProto* result = file->add_message_type();
81 result->set_name(name);
82 return result;
83 }
84
AddNestedMessage(DescriptorProto * parent,const std::string & name)85 DescriptorProto* AddNestedMessage(DescriptorProto* parent,
86 const std::string& name) {
87 DescriptorProto* result = parent->add_nested_type();
88 result->set_name(name);
89 return result;
90 }
91
AddEnum(FileDescriptorProto * file,const std::string & name)92 EnumDescriptorProto* AddEnum(FileDescriptorProto* file,
93 const std::string& name) {
94 EnumDescriptorProto* result = file->add_enum_type();
95 result->set_name(name);
96 return result;
97 }
98
AddNestedEnum(DescriptorProto * parent,const std::string & name)99 EnumDescriptorProto* AddNestedEnum(DescriptorProto* parent,
100 const std::string& name) {
101 EnumDescriptorProto* result = parent->add_enum_type();
102 result->set_name(name);
103 return result;
104 }
105
AddService(FileDescriptorProto * file,const std::string & name)106 ServiceDescriptorProto* AddService(FileDescriptorProto* file,
107 const std::string& name) {
108 ServiceDescriptorProto* result = file->add_service();
109 result->set_name(name);
110 return result;
111 }
112
AddField(DescriptorProto * parent,const std::string & name,int number,FieldDescriptorProto::Label label,FieldDescriptorProto::Type type)113 FieldDescriptorProto* AddField(DescriptorProto* parent, const std::string& name,
114 int number, FieldDescriptorProto::Label label,
115 FieldDescriptorProto::Type type) {
116 FieldDescriptorProto* result = parent->add_field();
117 result->set_name(name);
118 result->set_number(number);
119 result->set_label(label);
120 result->set_type(type);
121 return result;
122 }
123
AddExtension(FileDescriptorProto * file,const std::string & extendee,const std::string & name,int number,FieldDescriptorProto::Label label,FieldDescriptorProto::Type type)124 FieldDescriptorProto* AddExtension(FileDescriptorProto* file,
125 const std::string& extendee,
126 const std::string& name, int number,
127 FieldDescriptorProto::Label label,
128 FieldDescriptorProto::Type type) {
129 FieldDescriptorProto* result = file->add_extension();
130 result->set_name(name);
131 result->set_number(number);
132 result->set_label(label);
133 result->set_type(type);
134 result->set_extendee(extendee);
135 return result;
136 }
137
AddNestedExtension(DescriptorProto * parent,const std::string & extendee,const std::string & name,int number,FieldDescriptorProto::Label label,FieldDescriptorProto::Type type)138 FieldDescriptorProto* AddNestedExtension(DescriptorProto* parent,
139 const std::string& extendee,
140 const std::string& name, int number,
141 FieldDescriptorProto::Label label,
142 FieldDescriptorProto::Type type) {
143 FieldDescriptorProto* result = parent->add_extension();
144 result->set_name(name);
145 result->set_number(number);
146 result->set_label(label);
147 result->set_type(type);
148 result->set_extendee(extendee);
149 return result;
150 }
151
AddExtensionRange(DescriptorProto * parent,int start,int end)152 DescriptorProto::ExtensionRange* AddExtensionRange(DescriptorProto* parent,
153 int start, int end) {
154 DescriptorProto::ExtensionRange* result = parent->add_extension_range();
155 result->set_start(start);
156 result->set_end(end);
157 return result;
158 }
159
AddReservedRange(DescriptorProto * parent,int start,int end)160 DescriptorProto::ReservedRange* AddReservedRange(DescriptorProto* parent,
161 int start, int end) {
162 DescriptorProto::ReservedRange* result = parent->add_reserved_range();
163 result->set_start(start);
164 result->set_end(end);
165 return result;
166 }
167
AddReservedRange(EnumDescriptorProto * parent,int start,int end)168 EnumDescriptorProto::EnumReservedRange* AddReservedRange(
169 EnumDescriptorProto* parent, int start, int end) {
170 EnumDescriptorProto::EnumReservedRange* result = parent->add_reserved_range();
171 result->set_start(start);
172 result->set_end(end);
173 return result;
174 }
175
AddEnumValue(EnumDescriptorProto * enum_proto,const std::string & name,int number)176 EnumValueDescriptorProto* AddEnumValue(EnumDescriptorProto* enum_proto,
177 const std::string& name, int number) {
178 EnumValueDescriptorProto* result = enum_proto->add_value();
179 result->set_name(name);
180 result->set_number(number);
181 return result;
182 }
183
AddMethod(ServiceDescriptorProto * service,const std::string & name,const std::string & input_type,const std::string & output_type)184 MethodDescriptorProto* AddMethod(ServiceDescriptorProto* service,
185 const std::string& name,
186 const std::string& input_type,
187 const std::string& output_type) {
188 MethodDescriptorProto* result = service->add_method();
189 result->set_name(name);
190 result->set_input_type(input_type);
191 result->set_output_type(output_type);
192 return result;
193 }
194
195 // Empty enums technically aren't allowed. We need to insert a dummy value
196 // into them.
AddEmptyEnum(FileDescriptorProto * file,const std::string & name)197 void AddEmptyEnum(FileDescriptorProto* file, const std::string& name) {
198 AddEnumValue(AddEnum(file, name), name + "_DUMMY", 1);
199 }
200
201 class MockErrorCollector : public DescriptorPool::ErrorCollector {
202 public:
MockErrorCollector()203 MockErrorCollector() {}
~MockErrorCollector()204 ~MockErrorCollector() override {}
205
206 std::string text_;
207 std::string warning_text_;
208
209 // implements ErrorCollector ---------------------------------------
AddError(const std::string & filename,const std::string & element_name,const Message * descriptor,ErrorLocation location,const std::string & message)210 void AddError(const std::string& filename, const std::string& element_name,
211 const Message* descriptor, ErrorLocation location,
212 const std::string& message) override {
213 const char* location_name = nullptr;
214 switch (location) {
215 case NAME:
216 location_name = "NAME";
217 break;
218 case NUMBER:
219 location_name = "NUMBER";
220 break;
221 case TYPE:
222 location_name = "TYPE";
223 break;
224 case EXTENDEE:
225 location_name = "EXTENDEE";
226 break;
227 case DEFAULT_VALUE:
228 location_name = "DEFAULT_VALUE";
229 break;
230 case OPTION_NAME:
231 location_name = "OPTION_NAME";
232 break;
233 case OPTION_VALUE:
234 location_name = "OPTION_VALUE";
235 break;
236 case INPUT_TYPE:
237 location_name = "INPUT_TYPE";
238 break;
239 case OUTPUT_TYPE:
240 location_name = "OUTPUT_TYPE";
241 break;
242 case IMPORT:
243 location_name = "IMPORT";
244 break;
245 case OTHER:
246 location_name = "OTHER";
247 break;
248 }
249
250 strings::SubstituteAndAppend(&text_, "$0: $1: $2: $3\n", filename,
251 element_name, location_name, message);
252 }
253
254 // implements ErrorCollector ---------------------------------------
AddWarning(const std::string & filename,const std::string & element_name,const Message * descriptor,ErrorLocation location,const std::string & message)255 void AddWarning(const std::string& filename, const std::string& element_name,
256 const Message* descriptor, ErrorLocation location,
257 const std::string& message) override {
258 const char* location_name = nullptr;
259 switch (location) {
260 case NAME:
261 location_name = "NAME";
262 break;
263 case NUMBER:
264 location_name = "NUMBER";
265 break;
266 case TYPE:
267 location_name = "TYPE";
268 break;
269 case EXTENDEE:
270 location_name = "EXTENDEE";
271 break;
272 case DEFAULT_VALUE:
273 location_name = "DEFAULT_VALUE";
274 break;
275 case OPTION_NAME:
276 location_name = "OPTION_NAME";
277 break;
278 case OPTION_VALUE:
279 location_name = "OPTION_VALUE";
280 break;
281 case INPUT_TYPE:
282 location_name = "INPUT_TYPE";
283 break;
284 case OUTPUT_TYPE:
285 location_name = "OUTPUT_TYPE";
286 break;
287 case IMPORT:
288 location_name = "IMPORT";
289 break;
290 case OTHER:
291 location_name = "OTHER";
292 break;
293 }
294
295 strings::SubstituteAndAppend(&warning_text_, "$0: $1: $2: $3\n", filename,
296 element_name, location_name, message);
297 }
298 };
299
300 // ===================================================================
301
302 // Test simple files.
303 class FileDescriptorTest : public testing::Test {
304 protected:
SetUp()305 void SetUp() override {
306 // Build descriptors for the following definitions:
307 //
308 // // in "foo.proto"
309 // message FooMessage { extensions 1; }
310 // enum FooEnum {FOO_ENUM_VALUE = 1;}
311 // service FooService {}
312 // extend FooMessage { optional int32 foo_extension = 1; }
313 //
314 // // in "bar.proto"
315 // package bar_package;
316 // message BarMessage { extensions 1; }
317 // enum BarEnum {BAR_ENUM_VALUE = 1;}
318 // service BarService {}
319 // extend BarMessage { optional int32 bar_extension = 1; }
320 //
321 // Also, we have an empty file "baz.proto". This file's purpose is to
322 // make sure that even though it has the same package as foo.proto,
323 // searching it for members of foo.proto won't work.
324
325 FileDescriptorProto foo_file;
326 foo_file.set_name("foo.proto");
327 AddExtensionRange(AddMessage(&foo_file, "FooMessage"), 1, 2);
328 AddEnumValue(AddEnum(&foo_file, "FooEnum"), "FOO_ENUM_VALUE", 1);
329 AddService(&foo_file, "FooService");
330 AddExtension(&foo_file, "FooMessage", "foo_extension", 1,
331 FieldDescriptorProto::LABEL_OPTIONAL,
332 FieldDescriptorProto::TYPE_INT32);
333
334 FileDescriptorProto bar_file;
335 bar_file.set_name("bar.proto");
336 bar_file.set_package("bar_package");
337 bar_file.add_dependency("foo.proto");
338 AddExtensionRange(AddMessage(&bar_file, "BarMessage"), 1, 2);
339 AddEnumValue(AddEnum(&bar_file, "BarEnum"), "BAR_ENUM_VALUE", 1);
340 AddService(&bar_file, "BarService");
341 AddExtension(&bar_file, "bar_package.BarMessage", "bar_extension", 1,
342 FieldDescriptorProto::LABEL_OPTIONAL,
343 FieldDescriptorProto::TYPE_INT32);
344
345 FileDescriptorProto baz_file;
346 baz_file.set_name("baz.proto");
347
348 // Build the descriptors and get the pointers.
349 foo_file_ = pool_.BuildFile(foo_file);
350 ASSERT_TRUE(foo_file_ != nullptr);
351
352 bar_file_ = pool_.BuildFile(bar_file);
353 ASSERT_TRUE(bar_file_ != nullptr);
354
355 baz_file_ = pool_.BuildFile(baz_file);
356 ASSERT_TRUE(baz_file_ != nullptr);
357
358 ASSERT_EQ(1, foo_file_->message_type_count());
359 foo_message_ = foo_file_->message_type(0);
360 ASSERT_EQ(1, foo_file_->enum_type_count());
361 foo_enum_ = foo_file_->enum_type(0);
362 ASSERT_EQ(1, foo_enum_->value_count());
363 foo_enum_value_ = foo_enum_->value(0);
364 ASSERT_EQ(1, foo_file_->service_count());
365 foo_service_ = foo_file_->service(0);
366 ASSERT_EQ(1, foo_file_->extension_count());
367 foo_extension_ = foo_file_->extension(0);
368
369 ASSERT_EQ(1, bar_file_->message_type_count());
370 bar_message_ = bar_file_->message_type(0);
371 ASSERT_EQ(1, bar_file_->enum_type_count());
372 bar_enum_ = bar_file_->enum_type(0);
373 ASSERT_EQ(1, bar_enum_->value_count());
374 bar_enum_value_ = bar_enum_->value(0);
375 ASSERT_EQ(1, bar_file_->service_count());
376 bar_service_ = bar_file_->service(0);
377 ASSERT_EQ(1, bar_file_->extension_count());
378 bar_extension_ = bar_file_->extension(0);
379 }
380
381 DescriptorPool pool_;
382
383 const FileDescriptor* foo_file_;
384 const FileDescriptor* bar_file_;
385 const FileDescriptor* baz_file_;
386
387 const Descriptor* foo_message_;
388 const EnumDescriptor* foo_enum_;
389 const EnumValueDescriptor* foo_enum_value_;
390 const ServiceDescriptor* foo_service_;
391 const FieldDescriptor* foo_extension_;
392
393 const Descriptor* bar_message_;
394 const EnumDescriptor* bar_enum_;
395 const EnumValueDescriptor* bar_enum_value_;
396 const ServiceDescriptor* bar_service_;
397 const FieldDescriptor* bar_extension_;
398 };
399
TEST_F(FileDescriptorTest,Name)400 TEST_F(FileDescriptorTest, Name) {
401 EXPECT_EQ("foo.proto", foo_file_->name());
402 EXPECT_EQ("bar.proto", bar_file_->name());
403 EXPECT_EQ("baz.proto", baz_file_->name());
404 }
405
TEST_F(FileDescriptorTest,Package)406 TEST_F(FileDescriptorTest, Package) {
407 EXPECT_EQ("", foo_file_->package());
408 EXPECT_EQ("bar_package", bar_file_->package());
409 }
410
TEST_F(FileDescriptorTest,Dependencies)411 TEST_F(FileDescriptorTest, Dependencies) {
412 EXPECT_EQ(0, foo_file_->dependency_count());
413 EXPECT_EQ(1, bar_file_->dependency_count());
414 EXPECT_EQ(foo_file_, bar_file_->dependency(0));
415 }
416
TEST_F(FileDescriptorTest,FindMessageTypeByName)417 TEST_F(FileDescriptorTest, FindMessageTypeByName) {
418 EXPECT_EQ(foo_message_, foo_file_->FindMessageTypeByName("FooMessage"));
419 EXPECT_EQ(bar_message_, bar_file_->FindMessageTypeByName("BarMessage"));
420
421 EXPECT_TRUE(foo_file_->FindMessageTypeByName("BarMessage") == nullptr);
422 EXPECT_TRUE(bar_file_->FindMessageTypeByName("FooMessage") == nullptr);
423 EXPECT_TRUE(baz_file_->FindMessageTypeByName("FooMessage") == nullptr);
424
425 EXPECT_TRUE(foo_file_->FindMessageTypeByName("NoSuchMessage") == nullptr);
426 EXPECT_TRUE(foo_file_->FindMessageTypeByName("FooEnum") == nullptr);
427 }
428
TEST_F(FileDescriptorTest,FindEnumTypeByName)429 TEST_F(FileDescriptorTest, FindEnumTypeByName) {
430 EXPECT_EQ(foo_enum_, foo_file_->FindEnumTypeByName("FooEnum"));
431 EXPECT_EQ(bar_enum_, bar_file_->FindEnumTypeByName("BarEnum"));
432
433 EXPECT_TRUE(foo_file_->FindEnumTypeByName("BarEnum") == nullptr);
434 EXPECT_TRUE(bar_file_->FindEnumTypeByName("FooEnum") == nullptr);
435 EXPECT_TRUE(baz_file_->FindEnumTypeByName("FooEnum") == nullptr);
436
437 EXPECT_TRUE(foo_file_->FindEnumTypeByName("NoSuchEnum") == nullptr);
438 EXPECT_TRUE(foo_file_->FindEnumTypeByName("FooMessage") == nullptr);
439 }
440
TEST_F(FileDescriptorTest,FindEnumValueByName)441 TEST_F(FileDescriptorTest, FindEnumValueByName) {
442 EXPECT_EQ(foo_enum_value_, foo_file_->FindEnumValueByName("FOO_ENUM_VALUE"));
443 EXPECT_EQ(bar_enum_value_, bar_file_->FindEnumValueByName("BAR_ENUM_VALUE"));
444
445 EXPECT_TRUE(foo_file_->FindEnumValueByName("BAR_ENUM_VALUE") == nullptr);
446 EXPECT_TRUE(bar_file_->FindEnumValueByName("FOO_ENUM_VALUE") == nullptr);
447 EXPECT_TRUE(baz_file_->FindEnumValueByName("FOO_ENUM_VALUE") == nullptr);
448
449 EXPECT_TRUE(foo_file_->FindEnumValueByName("NO_SUCH_VALUE") == nullptr);
450 EXPECT_TRUE(foo_file_->FindEnumValueByName("FooMessage") == nullptr);
451 }
452
TEST_F(FileDescriptorTest,FindServiceByName)453 TEST_F(FileDescriptorTest, FindServiceByName) {
454 EXPECT_EQ(foo_service_, foo_file_->FindServiceByName("FooService"));
455 EXPECT_EQ(bar_service_, bar_file_->FindServiceByName("BarService"));
456
457 EXPECT_TRUE(foo_file_->FindServiceByName("BarService") == nullptr);
458 EXPECT_TRUE(bar_file_->FindServiceByName("FooService") == nullptr);
459 EXPECT_TRUE(baz_file_->FindServiceByName("FooService") == nullptr);
460
461 EXPECT_TRUE(foo_file_->FindServiceByName("NoSuchService") == nullptr);
462 EXPECT_TRUE(foo_file_->FindServiceByName("FooMessage") == nullptr);
463 }
464
TEST_F(FileDescriptorTest,FindExtensionByName)465 TEST_F(FileDescriptorTest, FindExtensionByName) {
466 EXPECT_EQ(foo_extension_, foo_file_->FindExtensionByName("foo_extension"));
467 EXPECT_EQ(bar_extension_, bar_file_->FindExtensionByName("bar_extension"));
468
469 EXPECT_TRUE(foo_file_->FindExtensionByName("bar_extension") == nullptr);
470 EXPECT_TRUE(bar_file_->FindExtensionByName("foo_extension") == nullptr);
471 EXPECT_TRUE(baz_file_->FindExtensionByName("foo_extension") == nullptr);
472
473 EXPECT_TRUE(foo_file_->FindExtensionByName("no_such_extension") == nullptr);
474 EXPECT_TRUE(foo_file_->FindExtensionByName("FooMessage") == nullptr);
475 }
476
TEST_F(FileDescriptorTest,FindExtensionByNumber)477 TEST_F(FileDescriptorTest, FindExtensionByNumber) {
478 EXPECT_EQ(foo_extension_, pool_.FindExtensionByNumber(foo_message_, 1));
479 EXPECT_EQ(bar_extension_, pool_.FindExtensionByNumber(bar_message_, 1));
480
481 EXPECT_TRUE(pool_.FindExtensionByNumber(foo_message_, 2) == nullptr);
482 }
483
484
TEST_F(FileDescriptorTest,BuildAgain)485 TEST_F(FileDescriptorTest, BuildAgain) {
486 // Test that if we call BuildFile again on the same input we get the same
487 // FileDescriptor back.
488 FileDescriptorProto file;
489 foo_file_->CopyTo(&file);
490 EXPECT_EQ(foo_file_, pool_.BuildFile(file));
491
492 // But if we change the file then it won't work.
493 file.set_package("some.other.package");
494 EXPECT_TRUE(pool_.BuildFile(file) == nullptr);
495 }
496
TEST_F(FileDescriptorTest,BuildAgainWithSyntax)497 TEST_F(FileDescriptorTest, BuildAgainWithSyntax) {
498 // Test that if we call BuildFile again on the same input we get the same
499 // FileDescriptor back even if syntax param is specified.
500 FileDescriptorProto proto_syntax2;
501 proto_syntax2.set_name("foo_syntax2");
502 proto_syntax2.set_syntax("proto2");
503
504 const FileDescriptor* proto2_descriptor = pool_.BuildFile(proto_syntax2);
505 EXPECT_TRUE(proto2_descriptor != nullptr);
506 EXPECT_EQ(proto2_descriptor, pool_.BuildFile(proto_syntax2));
507
508 FileDescriptorProto implicit_proto2;
509 implicit_proto2.set_name("foo_implicit_syntax2");
510
511 const FileDescriptor* implicit_proto2_descriptor =
512 pool_.BuildFile(implicit_proto2);
513 EXPECT_TRUE(implicit_proto2_descriptor != nullptr);
514 // We get the same FileDescriptor back if syntax param is explicitly
515 // specified.
516 implicit_proto2.set_syntax("proto2");
517 EXPECT_EQ(implicit_proto2_descriptor, pool_.BuildFile(implicit_proto2));
518
519 FileDescriptorProto proto_syntax3;
520 proto_syntax3.set_name("foo_syntax3");
521 proto_syntax3.set_syntax("proto3");
522
523 const FileDescriptor* proto3_descriptor = pool_.BuildFile(proto_syntax3);
524 EXPECT_TRUE(proto3_descriptor != nullptr);
525 EXPECT_EQ(proto3_descriptor, pool_.BuildFile(proto_syntax3));
526 }
527
TEST_F(FileDescriptorTest,Syntax)528 TEST_F(FileDescriptorTest, Syntax) {
529 FileDescriptorProto proto;
530 proto.set_name("foo");
531 // Enable the test when we also populate the syntax for proto2.
532 #if 0
533 {
534 proto.set_syntax("proto2");
535 DescriptorPool pool;
536 const FileDescriptor* file = pool.BuildFile(proto);
537 EXPECT_TRUE(file != nullptr);
538 EXPECT_EQ(FileDescriptor::SYNTAX_PROTO2, file->syntax());
539 FileDescriptorProto other;
540 file->CopyTo(&other);
541 EXPECT_EQ("proto2", other.syntax());
542 }
543 #endif
544 {
545 proto.set_syntax("proto3");
546 DescriptorPool pool;
547 const FileDescriptor* file = pool.BuildFile(proto);
548 EXPECT_TRUE(file != nullptr);
549 EXPECT_EQ(FileDescriptor::SYNTAX_PROTO3, file->syntax());
550 FileDescriptorProto other;
551 file->CopyTo(&other);
552 EXPECT_EQ("proto3", other.syntax());
553 }
554 }
555
ExtractDebugString(const FileDescriptor * file,std::set<std::string> * visited,std::vector<std::pair<std::string,std::string>> * debug_strings)556 void ExtractDebugString(
557 const FileDescriptor* file, std::set<std::string>* visited,
558 std::vector<std::pair<std::string, std::string>>* debug_strings) {
559 if (!visited->insert(file->name()).second) {
560 return;
561 }
562 for (int i = 0; i < file->dependency_count(); ++i) {
563 ExtractDebugString(file->dependency(i), visited, debug_strings);
564 }
565 debug_strings->push_back(std::make_pair(file->name(), file->DebugString()));
566 }
567
568 class SimpleErrorCollector : public io::ErrorCollector {
569 public:
570 // implements ErrorCollector ---------------------------------------
AddError(int line,int column,const std::string & message)571 void AddError(int line, int column, const std::string& message) override {
572 last_error_ = StringPrintf("%d:%d:", line, column) + message;
573 }
574
last_error()575 const std::string& last_error() { return last_error_; }
576
577 private:
578 std::string last_error_;
579 };
580 // Test that the result of FileDescriptor::DebugString() can be used to create
581 // the original descriptors.
TEST_F(FileDescriptorTest,DebugStringRoundTrip)582 TEST_F(FileDescriptorTest, DebugStringRoundTrip) {
583 std::set<std::string> visited;
584 std::vector<std::pair<std::string, std::string>> debug_strings;
585 ExtractDebugString(protobuf_unittest::TestAllTypes::descriptor()->file(),
586 &visited, &debug_strings);
587 ExtractDebugString(
588 protobuf_unittest::TestMessageWithCustomOptions::descriptor()->file(),
589 &visited, &debug_strings);
590 ExtractDebugString(proto3_arena_unittest::TestAllTypes::descriptor()->file(),
591 &visited, &debug_strings);
592 ASSERT_GE(debug_strings.size(), 3);
593
594 DescriptorPool pool;
595 for (int i = 0; i < debug_strings.size(); ++i) {
596 const std::string& name = debug_strings[i].first;
597 const std::string& content = debug_strings[i].second;
598 io::ArrayInputStream input_stream(content.data(), content.size());
599 SimpleErrorCollector error_collector;
600 io::Tokenizer tokenizer(&input_stream, &error_collector);
601 compiler::Parser parser;
602 parser.RecordErrorsTo(&error_collector);
603 FileDescriptorProto proto;
604 ASSERT_TRUE(parser.Parse(&tokenizer, &proto))
605 << error_collector.last_error() << "\n"
606 << content;
607 ASSERT_EQ("", error_collector.last_error());
608 proto.set_name(name);
609 const FileDescriptor* descriptor = pool.BuildFile(proto);
610 ASSERT_TRUE(descriptor != nullptr) << proto.DebugString();
611 EXPECT_EQ(content, descriptor->DebugString());
612 }
613 }
614
615 // ===================================================================
616
617 // Test simple flat messages and fields.
618 class DescriptorTest : public testing::Test {
619 protected:
SetUp()620 void SetUp() override {
621 // Build descriptors for the following definitions:
622 //
623 // // in "foo.proto"
624 // message TestForeign {}
625 // enum TestEnum {}
626 //
627 // message TestMessage {
628 // required string foo = 1;
629 // optional TestEnum bar = 6;
630 // repeated TestForeign baz = 500000000;
631 // optional group qux = 15 {}
632 // }
633 //
634 // // in "bar.proto"
635 // package corge.grault;
636 // message TestMessage2 {
637 // required string foo = 1;
638 // required string bar = 2;
639 // required string quux = 6;
640 // }
641 //
642 // // in "map.proto"
643 // message TestMessage3 {
644 // map<int32, int32> map_int32_int32 = 1;
645 // }
646 //
647 // // in "json.proto"
648 // message TestMessage4 {
649 // optional int32 field_name1 = 1;
650 // optional int32 fieldName2 = 2;
651 // optional int32 FieldName3 = 3;
652 // optional int32 _field_name4 = 4;
653 // optional int32 FIELD_NAME5 = 5;
654 // optional int32 field_name6 = 6 [json_name = "@type"];
655 // }
656 //
657 // We cheat and use TestForeign as the type for qux rather than create
658 // an actual nested type.
659 //
660 // Since all primitive types (including string) use the same building
661 // code, there's no need to test each one individually.
662 //
663 // TestMessage2 is primarily here to test FindFieldByName and friends.
664 // All messages created from the same DescriptorPool share the same lookup
665 // table, so we need to insure that they don't interfere.
666
667 FileDescriptorProto foo_file;
668 foo_file.set_name("foo.proto");
669 AddMessage(&foo_file, "TestForeign");
670 AddEmptyEnum(&foo_file, "TestEnum");
671
672 DescriptorProto* message = AddMessage(&foo_file, "TestMessage");
673 AddField(message, "foo", 1, FieldDescriptorProto::LABEL_REQUIRED,
674 FieldDescriptorProto::TYPE_STRING);
675 AddField(message, "bar", 6, FieldDescriptorProto::LABEL_OPTIONAL,
676 FieldDescriptorProto::TYPE_ENUM)
677 ->set_type_name("TestEnum");
678 AddField(message, "baz", 500000000, FieldDescriptorProto::LABEL_REPEATED,
679 FieldDescriptorProto::TYPE_MESSAGE)
680 ->set_type_name("TestForeign");
681 AddField(message, "qux", 15, FieldDescriptorProto::LABEL_OPTIONAL,
682 FieldDescriptorProto::TYPE_GROUP)
683 ->set_type_name("TestForeign");
684
685 FileDescriptorProto bar_file;
686 bar_file.set_name("bar.proto");
687 bar_file.set_package("corge.grault");
688
689 DescriptorProto* message2 = AddMessage(&bar_file, "TestMessage2");
690 AddField(message2, "foo", 1, FieldDescriptorProto::LABEL_REQUIRED,
691 FieldDescriptorProto::TYPE_STRING);
692 AddField(message2, "bar", 2, FieldDescriptorProto::LABEL_REQUIRED,
693 FieldDescriptorProto::TYPE_STRING);
694 AddField(message2, "quux", 6, FieldDescriptorProto::LABEL_REQUIRED,
695 FieldDescriptorProto::TYPE_STRING);
696
697 FileDescriptorProto map_file;
698 map_file.set_name("map.proto");
699 DescriptorProto* message3 = AddMessage(&map_file, "TestMessage3");
700
701 DescriptorProto* entry = AddNestedMessage(message3, "MapInt32Int32Entry");
702 AddField(entry, "key", 1, FieldDescriptorProto::LABEL_OPTIONAL,
703 FieldDescriptorProto::TYPE_INT32);
704 AddField(entry, "value", 2, FieldDescriptorProto::LABEL_OPTIONAL,
705 FieldDescriptorProto::TYPE_INT32);
706 entry->mutable_options()->set_map_entry(true);
707
708 AddField(message3, "map_int32_int32", 1,
709 FieldDescriptorProto::LABEL_REPEATED,
710 FieldDescriptorProto::TYPE_MESSAGE)
711 ->set_type_name("MapInt32Int32Entry");
712
713 FileDescriptorProto json_file;
714 json_file.set_name("json.proto");
715 json_file.set_syntax("proto3");
716 DescriptorProto* message4 = AddMessage(&json_file, "TestMessage4");
717 AddField(message4, "field_name1", 1, FieldDescriptorProto::LABEL_OPTIONAL,
718 FieldDescriptorProto::TYPE_INT32);
719 AddField(message4, "fieldName2", 2, FieldDescriptorProto::LABEL_OPTIONAL,
720 FieldDescriptorProto::TYPE_INT32);
721 AddField(message4, "FieldName3", 3, FieldDescriptorProto::LABEL_OPTIONAL,
722 FieldDescriptorProto::TYPE_INT32);
723 AddField(message4, "_field_name4", 4, FieldDescriptorProto::LABEL_OPTIONAL,
724 FieldDescriptorProto::TYPE_INT32);
725 AddField(message4, "FIELD_NAME5", 5, FieldDescriptorProto::LABEL_OPTIONAL,
726 FieldDescriptorProto::TYPE_INT32);
727 AddField(message4, "field_name6", 6, FieldDescriptorProto::LABEL_OPTIONAL,
728 FieldDescriptorProto::TYPE_INT32)
729 ->set_json_name("@type");
730 AddField(message4, "fieldname7", 7, FieldDescriptorProto::LABEL_OPTIONAL,
731 FieldDescriptorProto::TYPE_INT32);
732
733 // Build the descriptors and get the pointers.
734 foo_file_ = pool_.BuildFile(foo_file);
735 ASSERT_TRUE(foo_file_ != nullptr);
736
737 bar_file_ = pool_.BuildFile(bar_file);
738 ASSERT_TRUE(bar_file_ != nullptr);
739
740 map_file_ = pool_.BuildFile(map_file);
741 ASSERT_TRUE(map_file_ != nullptr);
742
743 json_file_ = pool_.BuildFile(json_file);
744 ASSERT_TRUE(json_file_ != nullptr);
745
746 ASSERT_EQ(1, foo_file_->enum_type_count());
747 enum_ = foo_file_->enum_type(0);
748
749 ASSERT_EQ(2, foo_file_->message_type_count());
750 foreign_ = foo_file_->message_type(0);
751 message_ = foo_file_->message_type(1);
752
753 ASSERT_EQ(4, message_->field_count());
754 foo_ = message_->field(0);
755 bar_ = message_->field(1);
756 baz_ = message_->field(2);
757 qux_ = message_->field(3);
758
759 ASSERT_EQ(1, bar_file_->message_type_count());
760 message2_ = bar_file_->message_type(0);
761
762 ASSERT_EQ(3, message2_->field_count());
763 foo2_ = message2_->field(0);
764 bar2_ = message2_->field(1);
765 quux2_ = message2_->field(2);
766
767 ASSERT_EQ(1, map_file_->message_type_count());
768 message3_ = map_file_->message_type(0);
769
770 ASSERT_EQ(1, message3_->field_count());
771 map_ = message3_->field(0);
772
773 ASSERT_EQ(1, json_file_->message_type_count());
774 message4_ = json_file_->message_type(0);
775 }
776
CopyWithJsonName(const Descriptor * message,DescriptorProto * proto)777 void CopyWithJsonName(const Descriptor* message, DescriptorProto* proto) {
778 message->CopyTo(proto);
779 message->CopyJsonNameTo(proto);
780 }
781
FindValueByNumberCreatingIfUnknown(const EnumDescriptor * desc,int number)782 const EnumValueDescriptor* FindValueByNumberCreatingIfUnknown(
783 const EnumDescriptor* desc, int number) {
784 return desc->FindValueByNumberCreatingIfUnknown(number);
785 }
786
787 DescriptorPool pool_;
788
789 const FileDescriptor* foo_file_;
790 const FileDescriptor* bar_file_;
791 const FileDescriptor* map_file_;
792 const FileDescriptor* json_file_;
793
794 const Descriptor* message_;
795 const Descriptor* message2_;
796 const Descriptor* message3_;
797 const Descriptor* message4_;
798 const Descriptor* foreign_;
799 const EnumDescriptor* enum_;
800
801 const FieldDescriptor* foo_;
802 const FieldDescriptor* bar_;
803 const FieldDescriptor* baz_;
804 const FieldDescriptor* qux_;
805
806 const FieldDescriptor* foo2_;
807 const FieldDescriptor* bar2_;
808 const FieldDescriptor* quux2_;
809
810 const FieldDescriptor* map_;
811 };
812
TEST_F(DescriptorTest,Name)813 TEST_F(DescriptorTest, Name) {
814 EXPECT_EQ("TestMessage", message_->name());
815 EXPECT_EQ("TestMessage", message_->full_name());
816 EXPECT_EQ(foo_file_, message_->file());
817
818 EXPECT_EQ("TestMessage2", message2_->name());
819 EXPECT_EQ("corge.grault.TestMessage2", message2_->full_name());
820 EXPECT_EQ(bar_file_, message2_->file());
821 }
822
TEST_F(DescriptorTest,ContainingType)823 TEST_F(DescriptorTest, ContainingType) {
824 EXPECT_TRUE(message_->containing_type() == nullptr);
825 EXPECT_TRUE(message2_->containing_type() == nullptr);
826 }
827
TEST_F(DescriptorTest,FieldNamesDedup)828 TEST_F(DescriptorTest, FieldNamesDedup) {
829 const auto collect_unique_names = [](const FieldDescriptor* field) {
830 std::set<std::string> names{field->name(), field->lowercase_name(),
831 field->camelcase_name(), field->json_name()};
832 // Verify that we have the same number of string objects as we have string
833 // values. That is, duplicate names use the same std::string object.
834 // This is for memory efficiency.
835 EXPECT_EQ(names.size(), (std::set<const std::string*>{
836 &field->name(), &field->lowercase_name(),
837 &field->camelcase_name(), &field->json_name()}
838 .size()))
839 << testing::PrintToString(names);
840 return names;
841 };
842
843 using testing::ElementsAre;
844 // field_name1
845 EXPECT_THAT(collect_unique_names(message4_->field(0)),
846 ElementsAre("fieldName1", "field_name1"));
847 // fieldName2
848 EXPECT_THAT(collect_unique_names(message4_->field(1)),
849 ElementsAre("fieldName2", "fieldname2"));
850 // FieldName3
851 EXPECT_THAT(collect_unique_names(message4_->field(2)),
852 ElementsAre("FieldName3", "fieldName3", "fieldname3"));
853 // _field_name4
854 EXPECT_THAT(collect_unique_names(message4_->field(3)),
855 ElementsAre("FieldName4", "_field_name4", "fieldName4"));
856 // FIELD_NAME5
857 EXPECT_THAT(
858 collect_unique_names(message4_->field(4)),
859 ElementsAre("FIELDNAME5", "FIELD_NAME5", "fIELDNAME5", "field_name5"));
860 // field_name6, with json name @type
861 EXPECT_THAT(collect_unique_names(message4_->field(5)),
862 ElementsAre("@type", "fieldName6", "field_name6"));
863 // fieldname7
864 EXPECT_THAT(collect_unique_names(message4_->field(6)),
865 ElementsAre("fieldname7"));
866 }
867
TEST_F(DescriptorTest,FieldNameDedupJsonEqFull)868 TEST_F(DescriptorTest, FieldNameDedupJsonEqFull) {
869 // Test a regression where json_name == full_name
870 FileDescriptorProto proto;
871 proto.set_name("file");
872 auto* message = AddMessage(&proto, "Name1");
873 auto* field =
874 AddField(message, "Name2", 1, FieldDescriptorProto::LABEL_OPTIONAL,
875 FieldDescriptorProto::TYPE_INT32);
876 field->set_json_name("Name1.Name2");
877 auto* file = pool_.BuildFile(proto);
878 EXPECT_EQ(file->message_type(0)->name(), "Name1");
879 EXPECT_EQ(file->message_type(0)->field(0)->name(), "Name2");
880 EXPECT_EQ(file->message_type(0)->field(0)->full_name(), "Name1.Name2");
881 EXPECT_EQ(file->message_type(0)->field(0)->json_name(), "Name1.Name2");
882 }
883
TEST_F(DescriptorTest,FieldsByIndex)884 TEST_F(DescriptorTest, FieldsByIndex) {
885 ASSERT_EQ(4, message_->field_count());
886 EXPECT_EQ(foo_, message_->field(0));
887 EXPECT_EQ(bar_, message_->field(1));
888 EXPECT_EQ(baz_, message_->field(2));
889 EXPECT_EQ(qux_, message_->field(3));
890 }
891
TEST_F(DescriptorTest,FindFieldByName)892 TEST_F(DescriptorTest, FindFieldByName) {
893 // All messages in the same DescriptorPool share a single lookup table for
894 // fields. So, in addition to testing that FindFieldByName finds the fields
895 // of the message, we need to test that it does *not* find the fields of
896 // *other* messages.
897
898 EXPECT_EQ(foo_, message_->FindFieldByName("foo"));
899 EXPECT_EQ(bar_, message_->FindFieldByName("bar"));
900 EXPECT_EQ(baz_, message_->FindFieldByName("baz"));
901 EXPECT_EQ(qux_, message_->FindFieldByName("qux"));
902 EXPECT_TRUE(message_->FindFieldByName("no_such_field") == nullptr);
903 EXPECT_TRUE(message_->FindFieldByName("quux") == nullptr);
904
905 EXPECT_EQ(foo2_, message2_->FindFieldByName("foo"));
906 EXPECT_EQ(bar2_, message2_->FindFieldByName("bar"));
907 EXPECT_EQ(quux2_, message2_->FindFieldByName("quux"));
908 EXPECT_TRUE(message2_->FindFieldByName("baz") == nullptr);
909 EXPECT_TRUE(message2_->FindFieldByName("qux") == nullptr);
910 }
911
TEST_F(DescriptorTest,FindFieldByNumber)912 TEST_F(DescriptorTest, FindFieldByNumber) {
913 EXPECT_EQ(foo_, message_->FindFieldByNumber(1));
914 EXPECT_EQ(bar_, message_->FindFieldByNumber(6));
915 EXPECT_EQ(baz_, message_->FindFieldByNumber(500000000));
916 EXPECT_EQ(qux_, message_->FindFieldByNumber(15));
917 EXPECT_TRUE(message_->FindFieldByNumber(837592) == nullptr);
918 EXPECT_TRUE(message_->FindFieldByNumber(2) == nullptr);
919
920 EXPECT_EQ(foo2_, message2_->FindFieldByNumber(1));
921 EXPECT_EQ(bar2_, message2_->FindFieldByNumber(2));
922 EXPECT_EQ(quux2_, message2_->FindFieldByNumber(6));
923 EXPECT_TRUE(message2_->FindFieldByNumber(15) == nullptr);
924 EXPECT_TRUE(message2_->FindFieldByNumber(500000000) == nullptr);
925 }
926
TEST_F(DescriptorTest,FieldName)927 TEST_F(DescriptorTest, FieldName) {
928 EXPECT_EQ("foo", foo_->name());
929 EXPECT_EQ("bar", bar_->name());
930 EXPECT_EQ("baz", baz_->name());
931 EXPECT_EQ("qux", qux_->name());
932 }
933
TEST_F(DescriptorTest,FieldFullName)934 TEST_F(DescriptorTest, FieldFullName) {
935 EXPECT_EQ("TestMessage.foo", foo_->full_name());
936 EXPECT_EQ("TestMessage.bar", bar_->full_name());
937 EXPECT_EQ("TestMessage.baz", baz_->full_name());
938 EXPECT_EQ("TestMessage.qux", qux_->full_name());
939
940 EXPECT_EQ("corge.grault.TestMessage2.foo", foo2_->full_name());
941 EXPECT_EQ("corge.grault.TestMessage2.bar", bar2_->full_name());
942 EXPECT_EQ("corge.grault.TestMessage2.quux", quux2_->full_name());
943 }
944
TEST_F(DescriptorTest,PrintableNameIsFullNameForNonExtensionFields)945 TEST_F(DescriptorTest, PrintableNameIsFullNameForNonExtensionFields) {
946 EXPECT_EQ("TestMessage.foo", foo_->PrintableNameForExtension());
947 EXPECT_EQ("TestMessage.bar", bar_->PrintableNameForExtension());
948 EXPECT_EQ("TestMessage.baz", baz_->PrintableNameForExtension());
949 EXPECT_EQ("TestMessage.qux", qux_->PrintableNameForExtension());
950
951 EXPECT_EQ("corge.grault.TestMessage2.foo",
952 foo2_->PrintableNameForExtension());
953 EXPECT_EQ("corge.grault.TestMessage2.bar",
954 bar2_->PrintableNameForExtension());
955 EXPECT_EQ("corge.grault.TestMessage2.quux",
956 quux2_->PrintableNameForExtension());
957 }
958
TEST_F(DescriptorTest,PrintableNameIsFullNameForNonMessageSetExtension)959 TEST_F(DescriptorTest, PrintableNameIsFullNameForNonMessageSetExtension) {
960 EXPECT_EQ("protobuf_unittest.Aggregate.nested",
961 protobuf_unittest::Aggregate::descriptor()
962 ->FindExtensionByName("nested")
963 ->PrintableNameForExtension());
964 }
965
TEST_F(DescriptorTest,PrintableNameIsExtendingTypeForMessageSetExtension)966 TEST_F(DescriptorTest, PrintableNameIsExtendingTypeForMessageSetExtension) {
967 EXPECT_EQ("protobuf_unittest.AggregateMessageSetElement",
968 protobuf_unittest::AggregateMessageSetElement::descriptor()
969 ->FindExtensionByName("message_set_extension")
970 ->PrintableNameForExtension());
971 }
972
TEST_F(DescriptorTest,FieldJsonName)973 TEST_F(DescriptorTest, FieldJsonName) {
974 EXPECT_EQ("fieldName1", message4_->field(0)->json_name());
975 EXPECT_EQ("fieldName2", message4_->field(1)->json_name());
976 EXPECT_EQ("FieldName3", message4_->field(2)->json_name());
977 EXPECT_EQ("FieldName4", message4_->field(3)->json_name());
978 EXPECT_EQ("FIELDNAME5", message4_->field(4)->json_name());
979 EXPECT_EQ("@type", message4_->field(5)->json_name());
980
981 DescriptorProto proto;
982 message4_->CopyTo(&proto);
983 ASSERT_EQ(7, proto.field_size());
984 EXPECT_FALSE(proto.field(0).has_json_name());
985 EXPECT_FALSE(proto.field(1).has_json_name());
986 EXPECT_FALSE(proto.field(2).has_json_name());
987 EXPECT_FALSE(proto.field(3).has_json_name());
988 EXPECT_FALSE(proto.field(4).has_json_name());
989 EXPECT_EQ("@type", proto.field(5).json_name());
990 EXPECT_FALSE(proto.field(6).has_json_name());
991
992 proto.Clear();
993 CopyWithJsonName(message4_, &proto);
994 ASSERT_EQ(7, proto.field_size());
995 EXPECT_EQ("fieldName1", proto.field(0).json_name());
996 EXPECT_EQ("fieldName2", proto.field(1).json_name());
997 EXPECT_EQ("FieldName3", proto.field(2).json_name());
998 EXPECT_EQ("FieldName4", proto.field(3).json_name());
999 EXPECT_EQ("FIELDNAME5", proto.field(4).json_name());
1000 EXPECT_EQ("@type", proto.field(5).json_name());
1001 EXPECT_EQ("fieldname7", proto.field(6).json_name());
1002
1003 // Test generated descriptor.
1004 const Descriptor* generated = protobuf_unittest::TestJsonName::descriptor();
1005 ASSERT_EQ(7, generated->field_count());
1006 EXPECT_EQ("fieldName1", generated->field(0)->json_name());
1007 EXPECT_EQ("fieldName2", generated->field(1)->json_name());
1008 EXPECT_EQ("FieldName3", generated->field(2)->json_name());
1009 EXPECT_EQ("FieldName4", generated->field(3)->json_name());
1010 EXPECT_EQ("FIELDNAME5", generated->field(4)->json_name());
1011 EXPECT_EQ("@type", generated->field(5)->json_name());
1012 EXPECT_EQ("fieldname7", generated->field(6)->json_name());
1013 }
1014
TEST_F(DescriptorTest,FieldFile)1015 TEST_F(DescriptorTest, FieldFile) {
1016 EXPECT_EQ(foo_file_, foo_->file());
1017 EXPECT_EQ(foo_file_, bar_->file());
1018 EXPECT_EQ(foo_file_, baz_->file());
1019 EXPECT_EQ(foo_file_, qux_->file());
1020
1021 EXPECT_EQ(bar_file_, foo2_->file());
1022 EXPECT_EQ(bar_file_, bar2_->file());
1023 EXPECT_EQ(bar_file_, quux2_->file());
1024 }
1025
TEST_F(DescriptorTest,FieldIndex)1026 TEST_F(DescriptorTest, FieldIndex) {
1027 EXPECT_EQ(0, foo_->index());
1028 EXPECT_EQ(1, bar_->index());
1029 EXPECT_EQ(2, baz_->index());
1030 EXPECT_EQ(3, qux_->index());
1031 }
1032
TEST_F(DescriptorTest,FieldNumber)1033 TEST_F(DescriptorTest, FieldNumber) {
1034 EXPECT_EQ(1, foo_->number());
1035 EXPECT_EQ(6, bar_->number());
1036 EXPECT_EQ(500000000, baz_->number());
1037 EXPECT_EQ(15, qux_->number());
1038 }
1039
TEST_F(DescriptorTest,FieldType)1040 TEST_F(DescriptorTest, FieldType) {
1041 EXPECT_EQ(FieldDescriptor::TYPE_STRING, foo_->type());
1042 EXPECT_EQ(FieldDescriptor::TYPE_ENUM, bar_->type());
1043 EXPECT_EQ(FieldDescriptor::TYPE_MESSAGE, baz_->type());
1044 EXPECT_EQ(FieldDescriptor::TYPE_GROUP, qux_->type());
1045 }
1046
TEST_F(DescriptorTest,FieldLabel)1047 TEST_F(DescriptorTest, FieldLabel) {
1048 EXPECT_EQ(FieldDescriptor::LABEL_REQUIRED, foo_->label());
1049 EXPECT_EQ(FieldDescriptor::LABEL_OPTIONAL, bar_->label());
1050 EXPECT_EQ(FieldDescriptor::LABEL_REPEATED, baz_->label());
1051 EXPECT_EQ(FieldDescriptor::LABEL_OPTIONAL, qux_->label());
1052
1053 EXPECT_TRUE(foo_->is_required());
1054 EXPECT_FALSE(foo_->is_optional());
1055 EXPECT_FALSE(foo_->is_repeated());
1056
1057 EXPECT_FALSE(bar_->is_required());
1058 EXPECT_TRUE(bar_->is_optional());
1059 EXPECT_FALSE(bar_->is_repeated());
1060
1061 EXPECT_FALSE(baz_->is_required());
1062 EXPECT_FALSE(baz_->is_optional());
1063 EXPECT_TRUE(baz_->is_repeated());
1064 }
1065
TEST_F(DescriptorTest,IsMap)1066 TEST_F(DescriptorTest, IsMap) {
1067 EXPECT_TRUE(map_->is_map());
1068 EXPECT_FALSE(baz_->is_map());
1069 EXPECT_TRUE(map_->message_type()->options().map_entry());
1070 }
1071
TEST_F(DescriptorTest,GetMap)1072 TEST_F(DescriptorTest, GetMap) {
1073 const Descriptor* map_desc = map_->message_type();
1074 const FieldDescriptor* map_key = map_desc->map_key();
1075 ASSERT_TRUE(map_key != nullptr);
1076 EXPECT_EQ(map_key->name(), "key");
1077 EXPECT_EQ(map_key->number(), 1);
1078
1079 const FieldDescriptor* map_value = map_desc->map_value();
1080 ASSERT_TRUE(map_value != nullptr);
1081 EXPECT_EQ(map_value->name(), "value");
1082 EXPECT_EQ(map_value->number(), 2);
1083
1084 EXPECT_EQ(message_->map_key(), nullptr);
1085 EXPECT_EQ(message_->map_value(), nullptr);
1086 }
1087
TEST_F(DescriptorTest,FieldHasDefault)1088 TEST_F(DescriptorTest, FieldHasDefault) {
1089 EXPECT_FALSE(foo_->has_default_value());
1090 EXPECT_FALSE(bar_->has_default_value());
1091 EXPECT_FALSE(baz_->has_default_value());
1092 EXPECT_FALSE(qux_->has_default_value());
1093 }
1094
TEST_F(DescriptorTest,FieldContainingType)1095 TEST_F(DescriptorTest, FieldContainingType) {
1096 EXPECT_EQ(message_, foo_->containing_type());
1097 EXPECT_EQ(message_, bar_->containing_type());
1098 EXPECT_EQ(message_, baz_->containing_type());
1099 EXPECT_EQ(message_, qux_->containing_type());
1100
1101 EXPECT_EQ(message2_, foo2_->containing_type());
1102 EXPECT_EQ(message2_, bar2_->containing_type());
1103 EXPECT_EQ(message2_, quux2_->containing_type());
1104 }
1105
TEST_F(DescriptorTest,FieldMessageType)1106 TEST_F(DescriptorTest, FieldMessageType) {
1107 EXPECT_TRUE(foo_->message_type() == nullptr);
1108 EXPECT_TRUE(bar_->message_type() == nullptr);
1109
1110 EXPECT_EQ(foreign_, baz_->message_type());
1111 EXPECT_EQ(foreign_, qux_->message_type());
1112 }
1113
TEST_F(DescriptorTest,FieldEnumType)1114 TEST_F(DescriptorTest, FieldEnumType) {
1115 EXPECT_TRUE(foo_->enum_type() == nullptr);
1116 EXPECT_TRUE(baz_->enum_type() == nullptr);
1117 EXPECT_TRUE(qux_->enum_type() == nullptr);
1118
1119 EXPECT_EQ(enum_, bar_->enum_type());
1120 }
1121
1122
1123 // ===================================================================
1124
1125 // Test simple flat messages and fields.
1126 class OneofDescriptorTest : public testing::Test {
1127 protected:
SetUp()1128 void SetUp() override {
1129 // Build descriptors for the following definitions:
1130 //
1131 // package garply;
1132 // message TestOneof {
1133 // optional int32 a = 1;
1134 // oneof foo {
1135 // string b = 2;
1136 // TestOneof c = 3;
1137 // }
1138 // oneof bar {
1139 // float d = 4;
1140 // }
1141 // }
1142
1143 FileDescriptorProto baz_file;
1144 baz_file.set_name("baz.proto");
1145 baz_file.set_package("garply");
1146
1147 DescriptorProto* oneof_message = AddMessage(&baz_file, "TestOneof");
1148 oneof_message->add_oneof_decl()->set_name("foo");
1149 oneof_message->add_oneof_decl()->set_name("bar");
1150
1151 AddField(oneof_message, "a", 1, FieldDescriptorProto::LABEL_OPTIONAL,
1152 FieldDescriptorProto::TYPE_INT32);
1153 AddField(oneof_message, "b", 2, FieldDescriptorProto::LABEL_OPTIONAL,
1154 FieldDescriptorProto::TYPE_STRING);
1155 oneof_message->mutable_field(1)->set_oneof_index(0);
1156 AddField(oneof_message, "c", 3, FieldDescriptorProto::LABEL_OPTIONAL,
1157 FieldDescriptorProto::TYPE_MESSAGE);
1158 oneof_message->mutable_field(2)->set_oneof_index(0);
1159 oneof_message->mutable_field(2)->set_type_name("TestOneof");
1160
1161 AddField(oneof_message, "d", 4, FieldDescriptorProto::LABEL_OPTIONAL,
1162 FieldDescriptorProto::TYPE_FLOAT);
1163 oneof_message->mutable_field(3)->set_oneof_index(1);
1164
1165 // Build the descriptors and get the pointers.
1166 baz_file_ = pool_.BuildFile(baz_file);
1167 ASSERT_TRUE(baz_file_ != nullptr);
1168
1169 ASSERT_EQ(1, baz_file_->message_type_count());
1170 oneof_message_ = baz_file_->message_type(0);
1171
1172 ASSERT_EQ(2, oneof_message_->oneof_decl_count());
1173 oneof_ = oneof_message_->oneof_decl(0);
1174 oneof2_ = oneof_message_->oneof_decl(1);
1175
1176 ASSERT_EQ(4, oneof_message_->field_count());
1177 a_ = oneof_message_->field(0);
1178 b_ = oneof_message_->field(1);
1179 c_ = oneof_message_->field(2);
1180 d_ = oneof_message_->field(3);
1181 }
1182
1183 DescriptorPool pool_;
1184
1185 const FileDescriptor* baz_file_;
1186
1187 const Descriptor* oneof_message_;
1188
1189 const OneofDescriptor* oneof_;
1190 const OneofDescriptor* oneof2_;
1191 const FieldDescriptor* a_;
1192 const FieldDescriptor* b_;
1193 const FieldDescriptor* c_;
1194 const FieldDescriptor* d_;
1195 };
1196
TEST_F(OneofDescriptorTest,Normal)1197 TEST_F(OneofDescriptorTest, Normal) {
1198 EXPECT_EQ("foo", oneof_->name());
1199 EXPECT_EQ("garply.TestOneof.foo", oneof_->full_name());
1200 EXPECT_EQ(0, oneof_->index());
1201 ASSERT_EQ(2, oneof_->field_count());
1202 EXPECT_EQ(b_, oneof_->field(0));
1203 EXPECT_EQ(c_, oneof_->field(1));
1204 EXPECT_TRUE(a_->containing_oneof() == nullptr);
1205 EXPECT_EQ(oneof_, b_->containing_oneof());
1206 EXPECT_EQ(oneof_, c_->containing_oneof());
1207 }
1208
TEST_F(OneofDescriptorTest,FindByName)1209 TEST_F(OneofDescriptorTest, FindByName) {
1210 EXPECT_EQ(oneof_, oneof_message_->FindOneofByName("foo"));
1211 EXPECT_EQ(oneof2_, oneof_message_->FindOneofByName("bar"));
1212 EXPECT_TRUE(oneof_message_->FindOneofByName("no_such_oneof") == nullptr);
1213 }
1214
1215 // ===================================================================
1216
1217 class StylizedFieldNamesTest : public testing::Test {
1218 protected:
SetUp()1219 void SetUp() override {
1220 FileDescriptorProto file;
1221 file.set_name("foo.proto");
1222
1223 AddExtensionRange(AddMessage(&file, "ExtendableMessage"), 1, 1000);
1224
1225 DescriptorProto* message = AddMessage(&file, "TestMessage");
1226 AddField(message, "foo_foo", 1, FieldDescriptorProto::LABEL_OPTIONAL,
1227 FieldDescriptorProto::TYPE_INT32);
1228 AddField(message, "FooBar", 2, FieldDescriptorProto::LABEL_OPTIONAL,
1229 FieldDescriptorProto::TYPE_INT32);
1230 AddField(message, "fooBaz", 3, FieldDescriptorProto::LABEL_OPTIONAL,
1231 FieldDescriptorProto::TYPE_INT32);
1232 AddField(message, "fooFoo", 4, // Camel-case conflict with foo_foo.
1233 FieldDescriptorProto::LABEL_OPTIONAL,
1234 FieldDescriptorProto::TYPE_INT32);
1235 AddField(message, "foobar", 5, // Lower-case conflict with FooBar.
1236 FieldDescriptorProto::LABEL_OPTIONAL,
1237 FieldDescriptorProto::TYPE_INT32);
1238
1239 AddNestedExtension(message, "ExtendableMessage", "bar_foo", 1,
1240 FieldDescriptorProto::LABEL_OPTIONAL,
1241 FieldDescriptorProto::TYPE_INT32);
1242 AddNestedExtension(message, "ExtendableMessage", "BarBar", 2,
1243 FieldDescriptorProto::LABEL_OPTIONAL,
1244 FieldDescriptorProto::TYPE_INT32);
1245 AddNestedExtension(message, "ExtendableMessage", "BarBaz", 3,
1246 FieldDescriptorProto::LABEL_OPTIONAL,
1247 FieldDescriptorProto::TYPE_INT32);
1248 AddNestedExtension(message, "ExtendableMessage", "barFoo", 4, // Conflict
1249 FieldDescriptorProto::LABEL_OPTIONAL,
1250 FieldDescriptorProto::TYPE_INT32);
1251 AddNestedExtension(message, "ExtendableMessage", "barbar", 5, // Conflict
1252 FieldDescriptorProto::LABEL_OPTIONAL,
1253 FieldDescriptorProto::TYPE_INT32);
1254
1255 AddExtension(&file, "ExtendableMessage", "baz_foo", 11,
1256 FieldDescriptorProto::LABEL_OPTIONAL,
1257 FieldDescriptorProto::TYPE_INT32);
1258 AddExtension(&file, "ExtendableMessage", "BazBar", 12,
1259 FieldDescriptorProto::LABEL_OPTIONAL,
1260 FieldDescriptorProto::TYPE_INT32);
1261 AddExtension(&file, "ExtendableMessage", "BazBaz", 13,
1262 FieldDescriptorProto::LABEL_OPTIONAL,
1263 FieldDescriptorProto::TYPE_INT32);
1264 AddExtension(&file, "ExtendableMessage", "bazFoo", 14, // Conflict
1265 FieldDescriptorProto::LABEL_OPTIONAL,
1266 FieldDescriptorProto::TYPE_INT32);
1267 AddExtension(&file, "ExtendableMessage", "bazbar", 15, // Conflict
1268 FieldDescriptorProto::LABEL_OPTIONAL,
1269 FieldDescriptorProto::TYPE_INT32);
1270
1271 file_ = pool_.BuildFile(file);
1272 ASSERT_TRUE(file_ != nullptr);
1273 ASSERT_EQ(2, file_->message_type_count());
1274 message_ = file_->message_type(1);
1275 ASSERT_EQ("TestMessage", message_->name());
1276 ASSERT_EQ(5, message_->field_count());
1277 ASSERT_EQ(5, message_->extension_count());
1278 ASSERT_EQ(5, file_->extension_count());
1279 }
1280
1281 DescriptorPool pool_;
1282 const FileDescriptor* file_;
1283 const Descriptor* message_;
1284 };
1285
TEST_F(StylizedFieldNamesTest,LowercaseName)1286 TEST_F(StylizedFieldNamesTest, LowercaseName) {
1287 EXPECT_EQ("foo_foo", message_->field(0)->lowercase_name());
1288 EXPECT_EQ("foobar", message_->field(1)->lowercase_name());
1289 EXPECT_EQ("foobaz", message_->field(2)->lowercase_name());
1290 EXPECT_EQ("foofoo", message_->field(3)->lowercase_name());
1291 EXPECT_EQ("foobar", message_->field(4)->lowercase_name());
1292
1293 EXPECT_EQ("bar_foo", message_->extension(0)->lowercase_name());
1294 EXPECT_EQ("barbar", message_->extension(1)->lowercase_name());
1295 EXPECT_EQ("barbaz", message_->extension(2)->lowercase_name());
1296 EXPECT_EQ("barfoo", message_->extension(3)->lowercase_name());
1297 EXPECT_EQ("barbar", message_->extension(4)->lowercase_name());
1298
1299 EXPECT_EQ("baz_foo", file_->extension(0)->lowercase_name());
1300 EXPECT_EQ("bazbar", file_->extension(1)->lowercase_name());
1301 EXPECT_EQ("bazbaz", file_->extension(2)->lowercase_name());
1302 EXPECT_EQ("bazfoo", file_->extension(3)->lowercase_name());
1303 EXPECT_EQ("bazbar", file_->extension(4)->lowercase_name());
1304 }
1305
TEST_F(StylizedFieldNamesTest,CamelcaseName)1306 TEST_F(StylizedFieldNamesTest, CamelcaseName) {
1307 EXPECT_EQ("fooFoo", message_->field(0)->camelcase_name());
1308 EXPECT_EQ("fooBar", message_->field(1)->camelcase_name());
1309 EXPECT_EQ("fooBaz", message_->field(2)->camelcase_name());
1310 EXPECT_EQ("fooFoo", message_->field(3)->camelcase_name());
1311 EXPECT_EQ("foobar", message_->field(4)->camelcase_name());
1312
1313 EXPECT_EQ("barFoo", message_->extension(0)->camelcase_name());
1314 EXPECT_EQ("barBar", message_->extension(1)->camelcase_name());
1315 EXPECT_EQ("barBaz", message_->extension(2)->camelcase_name());
1316 EXPECT_EQ("barFoo", message_->extension(3)->camelcase_name());
1317 EXPECT_EQ("barbar", message_->extension(4)->camelcase_name());
1318
1319 EXPECT_EQ("bazFoo", file_->extension(0)->camelcase_name());
1320 EXPECT_EQ("bazBar", file_->extension(1)->camelcase_name());
1321 EXPECT_EQ("bazBaz", file_->extension(2)->camelcase_name());
1322 EXPECT_EQ("bazFoo", file_->extension(3)->camelcase_name());
1323 EXPECT_EQ("bazbar", file_->extension(4)->camelcase_name());
1324 }
1325
TEST_F(StylizedFieldNamesTest,FindByLowercaseName)1326 TEST_F(StylizedFieldNamesTest, FindByLowercaseName) {
1327 EXPECT_EQ(message_->field(0), message_->FindFieldByLowercaseName("foo_foo"));
1328 EXPECT_THAT(message_->FindFieldByLowercaseName("foobar"),
1329 AnyOf(message_->field(1), message_->field(4)));
1330 EXPECT_EQ(message_->field(2), message_->FindFieldByLowercaseName("foobaz"));
1331 EXPECT_TRUE(message_->FindFieldByLowercaseName("FooBar") == nullptr);
1332 EXPECT_TRUE(message_->FindFieldByLowercaseName("fooBaz") == nullptr);
1333 EXPECT_TRUE(message_->FindFieldByLowercaseName("bar_foo") == nullptr);
1334 EXPECT_TRUE(message_->FindFieldByLowercaseName("nosuchfield") == nullptr);
1335
1336 EXPECT_EQ(message_->extension(0),
1337 message_->FindExtensionByLowercaseName("bar_foo"));
1338 EXPECT_THAT(message_->FindExtensionByLowercaseName("barbar"),
1339 AnyOf(message_->extension(1), message_->extension(4)));
1340 EXPECT_EQ(message_->extension(2),
1341 message_->FindExtensionByLowercaseName("barbaz"));
1342 EXPECT_TRUE(message_->FindExtensionByLowercaseName("BarBar") == nullptr);
1343 EXPECT_TRUE(message_->FindExtensionByLowercaseName("barBaz") == nullptr);
1344 EXPECT_TRUE(message_->FindExtensionByLowercaseName("foo_foo") == nullptr);
1345 EXPECT_TRUE(message_->FindExtensionByLowercaseName("nosuchfield") == nullptr);
1346
1347 EXPECT_EQ(file_->extension(0),
1348 file_->FindExtensionByLowercaseName("baz_foo"));
1349 EXPECT_THAT(file_->FindExtensionByLowercaseName("bazbar"),
1350 AnyOf(file_->extension(1), file_->extension(4)));
1351 EXPECT_EQ(file_->extension(2), file_->FindExtensionByLowercaseName("bazbaz"));
1352 EXPECT_TRUE(file_->FindExtensionByLowercaseName("BazBar") == nullptr);
1353 EXPECT_TRUE(file_->FindExtensionByLowercaseName("bazBaz") == nullptr);
1354 EXPECT_TRUE(file_->FindExtensionByLowercaseName("nosuchfield") == nullptr);
1355 }
1356
TEST_F(StylizedFieldNamesTest,FindByCamelcaseName)1357 TEST_F(StylizedFieldNamesTest, FindByCamelcaseName) {
1358 EXPECT_THAT(message_->FindFieldByCamelcaseName("fooFoo"),
1359 AnyOf(message_->field(0), message_->field(3)));
1360 EXPECT_EQ(message_->field(1), message_->FindFieldByCamelcaseName("fooBar"));
1361 EXPECT_EQ(message_->field(2), message_->FindFieldByCamelcaseName("fooBaz"));
1362 EXPECT_TRUE(message_->FindFieldByCamelcaseName("foo_foo") == nullptr);
1363 EXPECT_TRUE(message_->FindFieldByCamelcaseName("FooBar") == nullptr);
1364 EXPECT_TRUE(message_->FindFieldByCamelcaseName("barFoo") == nullptr);
1365 EXPECT_TRUE(message_->FindFieldByCamelcaseName("nosuchfield") == nullptr);
1366
1367 EXPECT_THAT(message_->FindExtensionByCamelcaseName("barFoo"),
1368 AnyOf(message_->extension(0), message_->extension(3)));
1369 EXPECT_EQ(message_->extension(1),
1370 message_->FindExtensionByCamelcaseName("barBar"));
1371 EXPECT_EQ(message_->extension(2),
1372 message_->FindExtensionByCamelcaseName("barBaz"));
1373 EXPECT_TRUE(message_->FindExtensionByCamelcaseName("bar_foo") == nullptr);
1374 EXPECT_TRUE(message_->FindExtensionByCamelcaseName("BarBar") == nullptr);
1375 EXPECT_TRUE(message_->FindExtensionByCamelcaseName("fooFoo") == nullptr);
1376 EXPECT_TRUE(message_->FindExtensionByCamelcaseName("nosuchfield") == nullptr);
1377
1378 EXPECT_THAT(file_->FindExtensionByCamelcaseName("bazFoo"),
1379 AnyOf(file_->extension(0), file_->extension(3)));
1380 EXPECT_EQ(file_->extension(1), file_->FindExtensionByCamelcaseName("bazBar"));
1381 EXPECT_EQ(file_->extension(2), file_->FindExtensionByCamelcaseName("bazBaz"));
1382 EXPECT_TRUE(file_->FindExtensionByCamelcaseName("baz_foo") == nullptr);
1383 EXPECT_TRUE(file_->FindExtensionByCamelcaseName("BazBar") == nullptr);
1384 EXPECT_TRUE(file_->FindExtensionByCamelcaseName("nosuchfield") == nullptr);
1385 }
1386
1387 // ===================================================================
1388
1389 // Test enum descriptors.
1390 class EnumDescriptorTest : public testing::Test {
1391 protected:
SetUp()1392 void SetUp() override {
1393 // Build descriptors for the following definitions:
1394 //
1395 // // in "foo.proto"
1396 // enum TestEnum {
1397 // FOO = 1;
1398 // BAR = 2;
1399 // }
1400 //
1401 // // in "bar.proto"
1402 // package corge.grault;
1403 // enum TestEnum2 {
1404 // FOO = 1;
1405 // BAZ = 3;
1406 // }
1407 //
1408 // TestEnum2 is primarily here to test FindValueByName and friends.
1409 // All enums created from the same DescriptorPool share the same lookup
1410 // table, so we need to insure that they don't interfere.
1411
1412 // TestEnum
1413 FileDescriptorProto foo_file;
1414 foo_file.set_name("foo.proto");
1415
1416 EnumDescriptorProto* enum_proto = AddEnum(&foo_file, "TestEnum");
1417 AddEnumValue(enum_proto, "FOO", 1);
1418 AddEnumValue(enum_proto, "BAR", 2);
1419
1420 // TestEnum2
1421 FileDescriptorProto bar_file;
1422 bar_file.set_name("bar.proto");
1423 bar_file.set_package("corge.grault");
1424
1425 EnumDescriptorProto* enum2_proto = AddEnum(&bar_file, "TestEnum2");
1426 AddEnumValue(enum2_proto, "FOO", 1);
1427 AddEnumValue(enum2_proto, "BAZ", 3);
1428
1429 // Build the descriptors and get the pointers.
1430 foo_file_ = pool_.BuildFile(foo_file);
1431 ASSERT_TRUE(foo_file_ != nullptr);
1432
1433 bar_file_ = pool_.BuildFile(bar_file);
1434 ASSERT_TRUE(bar_file_ != nullptr);
1435
1436 ASSERT_EQ(1, foo_file_->enum_type_count());
1437 enum_ = foo_file_->enum_type(0);
1438
1439 ASSERT_EQ(2, enum_->value_count());
1440 foo_ = enum_->value(0);
1441 bar_ = enum_->value(1);
1442
1443 ASSERT_EQ(1, bar_file_->enum_type_count());
1444 enum2_ = bar_file_->enum_type(0);
1445
1446 ASSERT_EQ(2, enum2_->value_count());
1447 foo2_ = enum2_->value(0);
1448 baz2_ = enum2_->value(1);
1449 }
1450
1451 DescriptorPool pool_;
1452
1453 const FileDescriptor* foo_file_;
1454 const FileDescriptor* bar_file_;
1455
1456 const EnumDescriptor* enum_;
1457 const EnumDescriptor* enum2_;
1458
1459 const EnumValueDescriptor* foo_;
1460 const EnumValueDescriptor* bar_;
1461
1462 const EnumValueDescriptor* foo2_;
1463 const EnumValueDescriptor* baz2_;
1464 };
1465
TEST_F(EnumDescriptorTest,Name)1466 TEST_F(EnumDescriptorTest, Name) {
1467 EXPECT_EQ("TestEnum", enum_->name());
1468 EXPECT_EQ("TestEnum", enum_->full_name());
1469 EXPECT_EQ(foo_file_, enum_->file());
1470
1471 EXPECT_EQ("TestEnum2", enum2_->name());
1472 EXPECT_EQ("corge.grault.TestEnum2", enum2_->full_name());
1473 EXPECT_EQ(bar_file_, enum2_->file());
1474 }
1475
TEST_F(EnumDescriptorTest,ContainingType)1476 TEST_F(EnumDescriptorTest, ContainingType) {
1477 EXPECT_TRUE(enum_->containing_type() == nullptr);
1478 EXPECT_TRUE(enum2_->containing_type() == nullptr);
1479 }
1480
TEST_F(EnumDescriptorTest,ValuesByIndex)1481 TEST_F(EnumDescriptorTest, ValuesByIndex) {
1482 ASSERT_EQ(2, enum_->value_count());
1483 EXPECT_EQ(foo_, enum_->value(0));
1484 EXPECT_EQ(bar_, enum_->value(1));
1485 }
1486
TEST_F(EnumDescriptorTest,FindValueByName)1487 TEST_F(EnumDescriptorTest, FindValueByName) {
1488 EXPECT_EQ(foo_, enum_->FindValueByName("FOO"));
1489 EXPECT_EQ(bar_, enum_->FindValueByName("BAR"));
1490 EXPECT_EQ(foo2_, enum2_->FindValueByName("FOO"));
1491 EXPECT_EQ(baz2_, enum2_->FindValueByName("BAZ"));
1492
1493 EXPECT_TRUE(enum_->FindValueByName("NO_SUCH_VALUE") == nullptr);
1494 EXPECT_TRUE(enum_->FindValueByName("BAZ") == nullptr);
1495 EXPECT_TRUE(enum2_->FindValueByName("BAR") == nullptr);
1496 }
1497
TEST_F(EnumDescriptorTest,FindValueByNumber)1498 TEST_F(EnumDescriptorTest, FindValueByNumber) {
1499 EXPECT_EQ(foo_, enum_->FindValueByNumber(1));
1500 EXPECT_EQ(bar_, enum_->FindValueByNumber(2));
1501 EXPECT_EQ(foo2_, enum2_->FindValueByNumber(1));
1502 EXPECT_EQ(baz2_, enum2_->FindValueByNumber(3));
1503
1504 EXPECT_TRUE(enum_->FindValueByNumber(416) == nullptr);
1505 EXPECT_TRUE(enum_->FindValueByNumber(3) == nullptr);
1506 EXPECT_TRUE(enum2_->FindValueByNumber(2) == nullptr);
1507 }
1508
TEST_F(EnumDescriptorTest,ValueName)1509 TEST_F(EnumDescriptorTest, ValueName) {
1510 EXPECT_EQ("FOO", foo_->name());
1511 EXPECT_EQ("BAR", bar_->name());
1512 }
1513
TEST_F(EnumDescriptorTest,ValueFullName)1514 TEST_F(EnumDescriptorTest, ValueFullName) {
1515 EXPECT_EQ("FOO", foo_->full_name());
1516 EXPECT_EQ("BAR", bar_->full_name());
1517 EXPECT_EQ("corge.grault.FOO", foo2_->full_name());
1518 EXPECT_EQ("corge.grault.BAZ", baz2_->full_name());
1519 }
1520
TEST_F(EnumDescriptorTest,ValueIndex)1521 TEST_F(EnumDescriptorTest, ValueIndex) {
1522 EXPECT_EQ(0, foo_->index());
1523 EXPECT_EQ(1, bar_->index());
1524 }
1525
TEST_F(EnumDescriptorTest,ValueNumber)1526 TEST_F(EnumDescriptorTest, ValueNumber) {
1527 EXPECT_EQ(1, foo_->number());
1528 EXPECT_EQ(2, bar_->number());
1529 }
1530
TEST_F(EnumDescriptorTest,ValueType)1531 TEST_F(EnumDescriptorTest, ValueType) {
1532 EXPECT_EQ(enum_, foo_->type());
1533 EXPECT_EQ(enum_, bar_->type());
1534 EXPECT_EQ(enum2_, foo2_->type());
1535 EXPECT_EQ(enum2_, baz2_->type());
1536 }
1537
1538 // ===================================================================
1539
1540 // Test service descriptors.
1541 class ServiceDescriptorTest : public testing::Test {
1542 protected:
SetUp()1543 void SetUp() override {
1544 // Build descriptors for the following messages and service:
1545 // // in "foo.proto"
1546 // message FooRequest {}
1547 // message FooResponse {}
1548 // message BarRequest {}
1549 // message BarResponse {}
1550 // message BazRequest {}
1551 // message BazResponse {}
1552 //
1553 // service TestService {
1554 // rpc Foo(FooRequest) returns (FooResponse);
1555 // rpc Bar(BarRequest) returns (BarResponse);
1556 // }
1557 //
1558 // // in "bar.proto"
1559 // package corge.grault
1560 // service TestService2 {
1561 // rpc Foo(FooRequest) returns (FooResponse);
1562 // rpc Baz(BazRequest) returns (BazResponse);
1563 // }
1564
1565 FileDescriptorProto foo_file;
1566 foo_file.set_name("foo.proto");
1567
1568 AddMessage(&foo_file, "FooRequest");
1569 AddMessage(&foo_file, "FooResponse");
1570 AddMessage(&foo_file, "BarRequest");
1571 AddMessage(&foo_file, "BarResponse");
1572 AddMessage(&foo_file, "BazRequest");
1573 AddMessage(&foo_file, "BazResponse");
1574
1575 ServiceDescriptorProto* service = AddService(&foo_file, "TestService");
1576 AddMethod(service, "Foo", "FooRequest", "FooResponse");
1577 AddMethod(service, "Bar", "BarRequest", "BarResponse");
1578
1579 FileDescriptorProto bar_file;
1580 bar_file.set_name("bar.proto");
1581 bar_file.set_package("corge.grault");
1582 bar_file.add_dependency("foo.proto");
1583
1584 ServiceDescriptorProto* service2 = AddService(&bar_file, "TestService2");
1585 AddMethod(service2, "Foo", "FooRequest", "FooResponse");
1586 AddMethod(service2, "Baz", "BazRequest", "BazResponse");
1587
1588 // Build the descriptors and get the pointers.
1589 foo_file_ = pool_.BuildFile(foo_file);
1590 ASSERT_TRUE(foo_file_ != nullptr);
1591
1592 bar_file_ = pool_.BuildFile(bar_file);
1593 ASSERT_TRUE(bar_file_ != nullptr);
1594
1595 ASSERT_EQ(6, foo_file_->message_type_count());
1596 foo_request_ = foo_file_->message_type(0);
1597 foo_response_ = foo_file_->message_type(1);
1598 bar_request_ = foo_file_->message_type(2);
1599 bar_response_ = foo_file_->message_type(3);
1600 baz_request_ = foo_file_->message_type(4);
1601 baz_response_ = foo_file_->message_type(5);
1602
1603 ASSERT_EQ(1, foo_file_->service_count());
1604 service_ = foo_file_->service(0);
1605
1606 ASSERT_EQ(2, service_->method_count());
1607 foo_ = service_->method(0);
1608 bar_ = service_->method(1);
1609
1610 ASSERT_EQ(1, bar_file_->service_count());
1611 service2_ = bar_file_->service(0);
1612
1613 ASSERT_EQ(2, service2_->method_count());
1614 foo2_ = service2_->method(0);
1615 baz2_ = service2_->method(1);
1616 }
1617
1618 DescriptorPool pool_;
1619
1620 const FileDescriptor* foo_file_;
1621 const FileDescriptor* bar_file_;
1622
1623 const Descriptor* foo_request_;
1624 const Descriptor* foo_response_;
1625 const Descriptor* bar_request_;
1626 const Descriptor* bar_response_;
1627 const Descriptor* baz_request_;
1628 const Descriptor* baz_response_;
1629
1630 const ServiceDescriptor* service_;
1631 const ServiceDescriptor* service2_;
1632
1633 const MethodDescriptor* foo_;
1634 const MethodDescriptor* bar_;
1635
1636 const MethodDescriptor* foo2_;
1637 const MethodDescriptor* baz2_;
1638 };
1639
TEST_F(ServiceDescriptorTest,Name)1640 TEST_F(ServiceDescriptorTest, Name) {
1641 EXPECT_EQ("TestService", service_->name());
1642 EXPECT_EQ("TestService", service_->full_name());
1643 EXPECT_EQ(foo_file_, service_->file());
1644
1645 EXPECT_EQ("TestService2", service2_->name());
1646 EXPECT_EQ("corge.grault.TestService2", service2_->full_name());
1647 EXPECT_EQ(bar_file_, service2_->file());
1648 }
1649
TEST_F(ServiceDescriptorTest,MethodsByIndex)1650 TEST_F(ServiceDescriptorTest, MethodsByIndex) {
1651 ASSERT_EQ(2, service_->method_count());
1652 EXPECT_EQ(foo_, service_->method(0));
1653 EXPECT_EQ(bar_, service_->method(1));
1654 }
1655
TEST_F(ServiceDescriptorTest,FindMethodByName)1656 TEST_F(ServiceDescriptorTest, FindMethodByName) {
1657 EXPECT_EQ(foo_, service_->FindMethodByName("Foo"));
1658 EXPECT_EQ(bar_, service_->FindMethodByName("Bar"));
1659 EXPECT_EQ(foo2_, service2_->FindMethodByName("Foo"));
1660 EXPECT_EQ(baz2_, service2_->FindMethodByName("Baz"));
1661
1662 EXPECT_TRUE(service_->FindMethodByName("NoSuchMethod") == nullptr);
1663 EXPECT_TRUE(service_->FindMethodByName("Baz") == nullptr);
1664 EXPECT_TRUE(service2_->FindMethodByName("Bar") == nullptr);
1665 }
1666
TEST_F(ServiceDescriptorTest,MethodName)1667 TEST_F(ServiceDescriptorTest, MethodName) {
1668 EXPECT_EQ("Foo", foo_->name());
1669 EXPECT_EQ("Bar", bar_->name());
1670 }
TEST_F(ServiceDescriptorTest,MethodFullName)1671 TEST_F(ServiceDescriptorTest, MethodFullName) {
1672 EXPECT_EQ("TestService.Foo", foo_->full_name());
1673 EXPECT_EQ("TestService.Bar", bar_->full_name());
1674 EXPECT_EQ("corge.grault.TestService2.Foo", foo2_->full_name());
1675 EXPECT_EQ("corge.grault.TestService2.Baz", baz2_->full_name());
1676 }
1677
TEST_F(ServiceDescriptorTest,MethodIndex)1678 TEST_F(ServiceDescriptorTest, MethodIndex) {
1679 EXPECT_EQ(0, foo_->index());
1680 EXPECT_EQ(1, bar_->index());
1681 }
1682
TEST_F(ServiceDescriptorTest,MethodParent)1683 TEST_F(ServiceDescriptorTest, MethodParent) {
1684 EXPECT_EQ(service_, foo_->service());
1685 EXPECT_EQ(service_, bar_->service());
1686 }
1687
TEST_F(ServiceDescriptorTest,MethodInputType)1688 TEST_F(ServiceDescriptorTest, MethodInputType) {
1689 EXPECT_EQ(foo_request_, foo_->input_type());
1690 EXPECT_EQ(bar_request_, bar_->input_type());
1691 }
1692
TEST_F(ServiceDescriptorTest,MethodOutputType)1693 TEST_F(ServiceDescriptorTest, MethodOutputType) {
1694 EXPECT_EQ(foo_response_, foo_->output_type());
1695 EXPECT_EQ(bar_response_, bar_->output_type());
1696 }
1697
1698 // ===================================================================
1699
1700 // Test nested types.
1701 class NestedDescriptorTest : public testing::Test {
1702 protected:
SetUp()1703 void SetUp() override {
1704 // Build descriptors for the following definitions:
1705 //
1706 // // in "foo.proto"
1707 // message TestMessage {
1708 // message Foo {}
1709 // message Bar {}
1710 // enum Baz { A = 1; }
1711 // enum Qux { B = 1; }
1712 // }
1713 //
1714 // // in "bar.proto"
1715 // package corge.grault;
1716 // message TestMessage2 {
1717 // message Foo {}
1718 // message Baz {}
1719 // enum Qux { A = 1; }
1720 // enum Quux { C = 1; }
1721 // }
1722 //
1723 // TestMessage2 is primarily here to test FindNestedTypeByName and friends.
1724 // All messages created from the same DescriptorPool share the same lookup
1725 // table, so we need to insure that they don't interfere.
1726 //
1727 // We add enum values to the enums in order to test searching for enum
1728 // values across a message's scope.
1729
1730 FileDescriptorProto foo_file;
1731 foo_file.set_name("foo.proto");
1732
1733 DescriptorProto* message = AddMessage(&foo_file, "TestMessage");
1734 AddNestedMessage(message, "Foo");
1735 AddNestedMessage(message, "Bar");
1736 EnumDescriptorProto* baz = AddNestedEnum(message, "Baz");
1737 AddEnumValue(baz, "A", 1);
1738 EnumDescriptorProto* qux = AddNestedEnum(message, "Qux");
1739 AddEnumValue(qux, "B", 1);
1740
1741 FileDescriptorProto bar_file;
1742 bar_file.set_name("bar.proto");
1743 bar_file.set_package("corge.grault");
1744
1745 DescriptorProto* message2 = AddMessage(&bar_file, "TestMessage2");
1746 AddNestedMessage(message2, "Foo");
1747 AddNestedMessage(message2, "Baz");
1748 EnumDescriptorProto* qux2 = AddNestedEnum(message2, "Qux");
1749 AddEnumValue(qux2, "A", 1);
1750 EnumDescriptorProto* quux2 = AddNestedEnum(message2, "Quux");
1751 AddEnumValue(quux2, "C", 1);
1752
1753 // Build the descriptors and get the pointers.
1754 foo_file_ = pool_.BuildFile(foo_file);
1755 ASSERT_TRUE(foo_file_ != nullptr);
1756
1757 bar_file_ = pool_.BuildFile(bar_file);
1758 ASSERT_TRUE(bar_file_ != nullptr);
1759
1760 ASSERT_EQ(1, foo_file_->message_type_count());
1761 message_ = foo_file_->message_type(0);
1762
1763 ASSERT_EQ(2, message_->nested_type_count());
1764 foo_ = message_->nested_type(0);
1765 bar_ = message_->nested_type(1);
1766
1767 ASSERT_EQ(2, message_->enum_type_count());
1768 baz_ = message_->enum_type(0);
1769 qux_ = message_->enum_type(1);
1770
1771 ASSERT_EQ(1, baz_->value_count());
1772 a_ = baz_->value(0);
1773 ASSERT_EQ(1, qux_->value_count());
1774 b_ = qux_->value(0);
1775
1776 ASSERT_EQ(1, bar_file_->message_type_count());
1777 message2_ = bar_file_->message_type(0);
1778
1779 ASSERT_EQ(2, message2_->nested_type_count());
1780 foo2_ = message2_->nested_type(0);
1781 baz2_ = message2_->nested_type(1);
1782
1783 ASSERT_EQ(2, message2_->enum_type_count());
1784 qux2_ = message2_->enum_type(0);
1785 quux2_ = message2_->enum_type(1);
1786
1787 ASSERT_EQ(1, qux2_->value_count());
1788 a2_ = qux2_->value(0);
1789 ASSERT_EQ(1, quux2_->value_count());
1790 c2_ = quux2_->value(0);
1791 }
1792
1793 DescriptorPool pool_;
1794
1795 const FileDescriptor* foo_file_;
1796 const FileDescriptor* bar_file_;
1797
1798 const Descriptor* message_;
1799 const Descriptor* message2_;
1800
1801 const Descriptor* foo_;
1802 const Descriptor* bar_;
1803 const EnumDescriptor* baz_;
1804 const EnumDescriptor* qux_;
1805 const EnumValueDescriptor* a_;
1806 const EnumValueDescriptor* b_;
1807
1808 const Descriptor* foo2_;
1809 const Descriptor* baz2_;
1810 const EnumDescriptor* qux2_;
1811 const EnumDescriptor* quux2_;
1812 const EnumValueDescriptor* a2_;
1813 const EnumValueDescriptor* c2_;
1814 };
1815
TEST_F(NestedDescriptorTest,MessageName)1816 TEST_F(NestedDescriptorTest, MessageName) {
1817 EXPECT_EQ("Foo", foo_->name());
1818 EXPECT_EQ("Bar", bar_->name());
1819 EXPECT_EQ("Foo", foo2_->name());
1820 EXPECT_EQ("Baz", baz2_->name());
1821
1822 EXPECT_EQ("TestMessage.Foo", foo_->full_name());
1823 EXPECT_EQ("TestMessage.Bar", bar_->full_name());
1824 EXPECT_EQ("corge.grault.TestMessage2.Foo", foo2_->full_name());
1825 EXPECT_EQ("corge.grault.TestMessage2.Baz", baz2_->full_name());
1826 }
1827
TEST_F(NestedDescriptorTest,MessageContainingType)1828 TEST_F(NestedDescriptorTest, MessageContainingType) {
1829 EXPECT_EQ(message_, foo_->containing_type());
1830 EXPECT_EQ(message_, bar_->containing_type());
1831 EXPECT_EQ(message2_, foo2_->containing_type());
1832 EXPECT_EQ(message2_, baz2_->containing_type());
1833 }
1834
TEST_F(NestedDescriptorTest,NestedMessagesByIndex)1835 TEST_F(NestedDescriptorTest, NestedMessagesByIndex) {
1836 ASSERT_EQ(2, message_->nested_type_count());
1837 EXPECT_EQ(foo_, message_->nested_type(0));
1838 EXPECT_EQ(bar_, message_->nested_type(1));
1839 }
1840
TEST_F(NestedDescriptorTest,FindFieldByNameDoesntFindNestedTypes)1841 TEST_F(NestedDescriptorTest, FindFieldByNameDoesntFindNestedTypes) {
1842 EXPECT_TRUE(message_->FindFieldByName("Foo") == nullptr);
1843 EXPECT_TRUE(message_->FindFieldByName("Qux") == nullptr);
1844 EXPECT_TRUE(message_->FindExtensionByName("Foo") == nullptr);
1845 EXPECT_TRUE(message_->FindExtensionByName("Qux") == nullptr);
1846 }
1847
TEST_F(NestedDescriptorTest,FindNestedTypeByName)1848 TEST_F(NestedDescriptorTest, FindNestedTypeByName) {
1849 EXPECT_EQ(foo_, message_->FindNestedTypeByName("Foo"));
1850 EXPECT_EQ(bar_, message_->FindNestedTypeByName("Bar"));
1851 EXPECT_EQ(foo2_, message2_->FindNestedTypeByName("Foo"));
1852 EXPECT_EQ(baz2_, message2_->FindNestedTypeByName("Baz"));
1853
1854 EXPECT_TRUE(message_->FindNestedTypeByName("NoSuchType") == nullptr);
1855 EXPECT_TRUE(message_->FindNestedTypeByName("Baz") == nullptr);
1856 EXPECT_TRUE(message2_->FindNestedTypeByName("Bar") == nullptr);
1857
1858 EXPECT_TRUE(message_->FindNestedTypeByName("Qux") == nullptr);
1859 }
1860
TEST_F(NestedDescriptorTest,EnumName)1861 TEST_F(NestedDescriptorTest, EnumName) {
1862 EXPECT_EQ("Baz", baz_->name());
1863 EXPECT_EQ("Qux", qux_->name());
1864 EXPECT_EQ("Qux", qux2_->name());
1865 EXPECT_EQ("Quux", quux2_->name());
1866
1867 EXPECT_EQ("TestMessage.Baz", baz_->full_name());
1868 EXPECT_EQ("TestMessage.Qux", qux_->full_name());
1869 EXPECT_EQ("corge.grault.TestMessage2.Qux", qux2_->full_name());
1870 EXPECT_EQ("corge.grault.TestMessage2.Quux", quux2_->full_name());
1871 }
1872
TEST_F(NestedDescriptorTest,EnumContainingType)1873 TEST_F(NestedDescriptorTest, EnumContainingType) {
1874 EXPECT_EQ(message_, baz_->containing_type());
1875 EXPECT_EQ(message_, qux_->containing_type());
1876 EXPECT_EQ(message2_, qux2_->containing_type());
1877 EXPECT_EQ(message2_, quux2_->containing_type());
1878 }
1879
TEST_F(NestedDescriptorTest,NestedEnumsByIndex)1880 TEST_F(NestedDescriptorTest, NestedEnumsByIndex) {
1881 ASSERT_EQ(2, message_->nested_type_count());
1882 EXPECT_EQ(foo_, message_->nested_type(0));
1883 EXPECT_EQ(bar_, message_->nested_type(1));
1884 }
1885
TEST_F(NestedDescriptorTest,FindEnumTypeByName)1886 TEST_F(NestedDescriptorTest, FindEnumTypeByName) {
1887 EXPECT_EQ(baz_, message_->FindEnumTypeByName("Baz"));
1888 EXPECT_EQ(qux_, message_->FindEnumTypeByName("Qux"));
1889 EXPECT_EQ(qux2_, message2_->FindEnumTypeByName("Qux"));
1890 EXPECT_EQ(quux2_, message2_->FindEnumTypeByName("Quux"));
1891
1892 EXPECT_TRUE(message_->FindEnumTypeByName("NoSuchType") == nullptr);
1893 EXPECT_TRUE(message_->FindEnumTypeByName("Quux") == nullptr);
1894 EXPECT_TRUE(message2_->FindEnumTypeByName("Baz") == nullptr);
1895
1896 EXPECT_TRUE(message_->FindEnumTypeByName("Foo") == nullptr);
1897 }
1898
TEST_F(NestedDescriptorTest,FindEnumValueByName)1899 TEST_F(NestedDescriptorTest, FindEnumValueByName) {
1900 EXPECT_EQ(a_, message_->FindEnumValueByName("A"));
1901 EXPECT_EQ(b_, message_->FindEnumValueByName("B"));
1902 EXPECT_EQ(a2_, message2_->FindEnumValueByName("A"));
1903 EXPECT_EQ(c2_, message2_->FindEnumValueByName("C"));
1904
1905 EXPECT_TRUE(message_->FindEnumValueByName("NO_SUCH_VALUE") == nullptr);
1906 EXPECT_TRUE(message_->FindEnumValueByName("C") == nullptr);
1907 EXPECT_TRUE(message2_->FindEnumValueByName("B") == nullptr);
1908
1909 EXPECT_TRUE(message_->FindEnumValueByName("Foo") == nullptr);
1910 }
1911
1912 // ===================================================================
1913
1914 // Test extensions.
1915 class ExtensionDescriptorTest : public testing::Test {
1916 protected:
SetUp()1917 void SetUp() override {
1918 // Build descriptors for the following definitions:
1919 //
1920 // enum Baz {}
1921 // message Qux {}
1922 //
1923 // message Foo {
1924 // extensions 10 to 19;
1925 // extensions 30 to 39;
1926 // }
1927 // extend Foo {
1928 // optional int32 foo_int32 = 10;
1929 // }
1930 // extend Foo {
1931 // repeated TestEnum foo_enum = 19;
1932 // }
1933 // message Bar {
1934 // optional int32 non_ext_int32 = 1;
1935 // extend Foo {
1936 // optional Qux foo_message = 30;
1937 // repeated Qux foo_group = 39; // (but internally set to TYPE_GROUP)
1938 // }
1939 // }
1940
1941 FileDescriptorProto foo_file;
1942 foo_file.set_name("foo.proto");
1943
1944 AddEmptyEnum(&foo_file, "Baz");
1945 AddMessage(&foo_file, "Qux");
1946
1947 DescriptorProto* foo = AddMessage(&foo_file, "Foo");
1948 AddExtensionRange(foo, 10, 20);
1949 AddExtensionRange(foo, 30, 40);
1950
1951 AddExtension(&foo_file, "Foo", "foo_int32", 10,
1952 FieldDescriptorProto::LABEL_OPTIONAL,
1953 FieldDescriptorProto::TYPE_INT32);
1954 AddExtension(&foo_file, "Foo", "foo_enum", 19,
1955 FieldDescriptorProto::LABEL_REPEATED,
1956 FieldDescriptorProto::TYPE_ENUM)
1957 ->set_type_name("Baz");
1958
1959 DescriptorProto* bar = AddMessage(&foo_file, "Bar");
1960 AddField(bar, "non_ext_int32", 1, FieldDescriptorProto::LABEL_OPTIONAL,
1961 FieldDescriptorProto::TYPE_INT32);
1962 AddNestedExtension(bar, "Foo", "foo_message", 30,
1963 FieldDescriptorProto::LABEL_OPTIONAL,
1964 FieldDescriptorProto::TYPE_MESSAGE)
1965 ->set_type_name("Qux");
1966 AddNestedExtension(bar, "Foo", "foo_group", 39,
1967 FieldDescriptorProto::LABEL_REPEATED,
1968 FieldDescriptorProto::TYPE_GROUP)
1969 ->set_type_name("Qux");
1970
1971 // Build the descriptors and get the pointers.
1972 foo_file_ = pool_.BuildFile(foo_file);
1973 ASSERT_TRUE(foo_file_ != nullptr);
1974
1975 ASSERT_EQ(1, foo_file_->enum_type_count());
1976 baz_ = foo_file_->enum_type(0);
1977
1978 ASSERT_EQ(3, foo_file_->message_type_count());
1979 qux_ = foo_file_->message_type(0);
1980 foo_ = foo_file_->message_type(1);
1981 bar_ = foo_file_->message_type(2);
1982 }
1983
1984 DescriptorPool pool_;
1985
1986 const FileDescriptor* foo_file_;
1987
1988 const Descriptor* foo_;
1989 const Descriptor* bar_;
1990 const EnumDescriptor* baz_;
1991 const Descriptor* qux_;
1992 };
1993
TEST_F(ExtensionDescriptorTest,ExtensionRanges)1994 TEST_F(ExtensionDescriptorTest, ExtensionRanges) {
1995 EXPECT_EQ(0, bar_->extension_range_count());
1996 ASSERT_EQ(2, foo_->extension_range_count());
1997
1998 EXPECT_EQ(10, foo_->extension_range(0)->start);
1999 EXPECT_EQ(30, foo_->extension_range(1)->start);
2000
2001 EXPECT_EQ(20, foo_->extension_range(0)->end);
2002 EXPECT_EQ(40, foo_->extension_range(1)->end);
2003 }
2004
TEST_F(ExtensionDescriptorTest,Extensions)2005 TEST_F(ExtensionDescriptorTest, Extensions) {
2006 EXPECT_EQ(0, foo_->extension_count());
2007 ASSERT_EQ(2, foo_file_->extension_count());
2008 ASSERT_EQ(2, bar_->extension_count());
2009
2010 EXPECT_TRUE(foo_file_->extension(0)->is_extension());
2011 EXPECT_TRUE(foo_file_->extension(1)->is_extension());
2012 EXPECT_TRUE(bar_->extension(0)->is_extension());
2013 EXPECT_TRUE(bar_->extension(1)->is_extension());
2014
2015 EXPECT_EQ("foo_int32", foo_file_->extension(0)->name());
2016 EXPECT_EQ("foo_enum", foo_file_->extension(1)->name());
2017 EXPECT_EQ("foo_message", bar_->extension(0)->name());
2018 EXPECT_EQ("foo_group", bar_->extension(1)->name());
2019
2020 EXPECT_EQ(10, foo_file_->extension(0)->number());
2021 EXPECT_EQ(19, foo_file_->extension(1)->number());
2022 EXPECT_EQ(30, bar_->extension(0)->number());
2023 EXPECT_EQ(39, bar_->extension(1)->number());
2024
2025 EXPECT_EQ(FieldDescriptor::TYPE_INT32, foo_file_->extension(0)->type());
2026 EXPECT_EQ(FieldDescriptor::TYPE_ENUM, foo_file_->extension(1)->type());
2027 EXPECT_EQ(FieldDescriptor::TYPE_MESSAGE, bar_->extension(0)->type());
2028 EXPECT_EQ(FieldDescriptor::TYPE_GROUP, bar_->extension(1)->type());
2029
2030 EXPECT_EQ(baz_, foo_file_->extension(1)->enum_type());
2031 EXPECT_EQ(qux_, bar_->extension(0)->message_type());
2032 EXPECT_EQ(qux_, bar_->extension(1)->message_type());
2033
2034 EXPECT_EQ(FieldDescriptor::LABEL_OPTIONAL, foo_file_->extension(0)->label());
2035 EXPECT_EQ(FieldDescriptor::LABEL_REPEATED, foo_file_->extension(1)->label());
2036 EXPECT_EQ(FieldDescriptor::LABEL_OPTIONAL, bar_->extension(0)->label());
2037 EXPECT_EQ(FieldDescriptor::LABEL_REPEATED, bar_->extension(1)->label());
2038
2039 EXPECT_EQ(foo_, foo_file_->extension(0)->containing_type());
2040 EXPECT_EQ(foo_, foo_file_->extension(1)->containing_type());
2041 EXPECT_EQ(foo_, bar_->extension(0)->containing_type());
2042 EXPECT_EQ(foo_, bar_->extension(1)->containing_type());
2043
2044 EXPECT_TRUE(foo_file_->extension(0)->extension_scope() == nullptr);
2045 EXPECT_TRUE(foo_file_->extension(1)->extension_scope() == nullptr);
2046 EXPECT_EQ(bar_, bar_->extension(0)->extension_scope());
2047 EXPECT_EQ(bar_, bar_->extension(1)->extension_scope());
2048 }
2049
TEST_F(ExtensionDescriptorTest,IsExtensionNumber)2050 TEST_F(ExtensionDescriptorTest, IsExtensionNumber) {
2051 EXPECT_FALSE(foo_->IsExtensionNumber(9));
2052 EXPECT_TRUE(foo_->IsExtensionNumber(10));
2053 EXPECT_TRUE(foo_->IsExtensionNumber(19));
2054 EXPECT_FALSE(foo_->IsExtensionNumber(20));
2055 EXPECT_FALSE(foo_->IsExtensionNumber(29));
2056 EXPECT_TRUE(foo_->IsExtensionNumber(30));
2057 EXPECT_TRUE(foo_->IsExtensionNumber(39));
2058 EXPECT_FALSE(foo_->IsExtensionNumber(40));
2059 }
2060
TEST_F(ExtensionDescriptorTest,FindExtensionByName)2061 TEST_F(ExtensionDescriptorTest, FindExtensionByName) {
2062 // Note that FileDescriptor::FindExtensionByName() is tested by
2063 // FileDescriptorTest.
2064 ASSERT_EQ(2, bar_->extension_count());
2065
2066 EXPECT_EQ(bar_->extension(0), bar_->FindExtensionByName("foo_message"));
2067 EXPECT_EQ(bar_->extension(1), bar_->FindExtensionByName("foo_group"));
2068
2069 EXPECT_TRUE(bar_->FindExtensionByName("no_such_extension") == nullptr);
2070 EXPECT_TRUE(foo_->FindExtensionByName("foo_int32") == nullptr);
2071 EXPECT_TRUE(foo_->FindExtensionByName("foo_message") == nullptr);
2072 }
2073
TEST_F(ExtensionDescriptorTest,FieldVsExtension)2074 TEST_F(ExtensionDescriptorTest, FieldVsExtension) {
2075 EXPECT_EQ(foo_->FindFieldByName("foo_message"), nullptr);
2076 EXPECT_EQ(bar_->FindFieldByName("foo_message"), nullptr);
2077 EXPECT_NE(bar_->FindFieldByName("non_ext_int32"), nullptr);
2078 EXPECT_EQ(foo_->FindExtensionByName("foo_message"), nullptr);
2079 EXPECT_NE(bar_->FindExtensionByName("foo_message"), nullptr);
2080 EXPECT_EQ(bar_->FindExtensionByName("non_ext_int32"), nullptr);
2081 }
2082
TEST_F(ExtensionDescriptorTest,FindExtensionByPrintableName)2083 TEST_F(ExtensionDescriptorTest, FindExtensionByPrintableName) {
2084 EXPECT_TRUE(pool_.FindExtensionByPrintableName(foo_, "no_such_extension") ==
2085 nullptr);
2086 EXPECT_TRUE(pool_.FindExtensionByPrintableName(bar_, "no_such_extension") ==
2087 nullptr);
2088
2089 ASSERT_FALSE(pool_.FindExtensionByPrintableName(foo_, "Bar.foo_message") ==
2090 nullptr);
2091 ASSERT_FALSE(pool_.FindExtensionByPrintableName(foo_, "Bar.foo_group") ==
2092 nullptr);
2093 EXPECT_TRUE(pool_.FindExtensionByPrintableName(bar_, "foo_message") ==
2094 nullptr);
2095 EXPECT_TRUE(pool_.FindExtensionByPrintableName(bar_, "foo_group") == nullptr);
2096 EXPECT_EQ(bar_->FindExtensionByName("foo_message"),
2097 pool_.FindExtensionByPrintableName(foo_, "Bar.foo_message"));
2098 EXPECT_EQ(bar_->FindExtensionByName("foo_group"),
2099 pool_.FindExtensionByPrintableName(foo_, "Bar.foo_group"));
2100
2101 ASSERT_FALSE(pool_.FindExtensionByPrintableName(foo_, "foo_int32") ==
2102 nullptr);
2103 ASSERT_FALSE(pool_.FindExtensionByPrintableName(foo_, "foo_enum") == nullptr);
2104 EXPECT_TRUE(pool_.FindExtensionByPrintableName(bar_, "foo_int32") == nullptr);
2105 EXPECT_TRUE(pool_.FindExtensionByPrintableName(bar_, "foo_enum") == nullptr);
2106 EXPECT_EQ(foo_file_->FindExtensionByName("foo_int32"),
2107 pool_.FindExtensionByPrintableName(foo_, "foo_int32"));
2108 EXPECT_EQ(foo_file_->FindExtensionByName("foo_enum"),
2109 pool_.FindExtensionByPrintableName(foo_, "foo_enum"));
2110 }
2111
TEST_F(ExtensionDescriptorTest,FindAllExtensions)2112 TEST_F(ExtensionDescriptorTest, FindAllExtensions) {
2113 std::vector<const FieldDescriptor*> extensions;
2114 pool_.FindAllExtensions(foo_, &extensions);
2115 ASSERT_EQ(4, extensions.size());
2116 EXPECT_EQ(10, extensions[0]->number());
2117 EXPECT_EQ(19, extensions[1]->number());
2118 EXPECT_EQ(30, extensions[2]->number());
2119 EXPECT_EQ(39, extensions[3]->number());
2120 }
2121
2122
TEST_F(ExtensionDescriptorTest,DuplicateFieldNumber)2123 TEST_F(ExtensionDescriptorTest, DuplicateFieldNumber) {
2124 DescriptorPool pool;
2125 FileDescriptorProto file_proto;
2126 // Add "google/protobuf/descriptor.proto".
2127 FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto);
2128 ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
2129 // Add "foo.proto":
2130 // import "google/protobuf/descriptor.proto";
2131 // extend google.protobuf.FieldOptions {
2132 // optional int32 option1 = 1000;
2133 // }
2134 file_proto.Clear();
2135 file_proto.set_name("foo.proto");
2136 file_proto.add_dependency("google/protobuf/descriptor.proto");
2137 AddExtension(&file_proto, "google.protobuf.FieldOptions", "option1", 1000,
2138 FieldDescriptorProto::LABEL_OPTIONAL,
2139 FieldDescriptorProto::TYPE_INT32);
2140 ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
2141 // Add "bar.proto":
2142 // import "google/protobuf/descriptor.proto";
2143 // extend google.protobuf.FieldOptions {
2144 // optional int32 option2 = 1000;
2145 // }
2146 file_proto.Clear();
2147 file_proto.set_name("bar.proto");
2148 file_proto.add_dependency("google/protobuf/descriptor.proto");
2149 AddExtension(&file_proto, "google.protobuf.FieldOptions", "option2", 1000,
2150 FieldDescriptorProto::LABEL_OPTIONAL,
2151 FieldDescriptorProto::TYPE_INT32);
2152 // Currently we only generate a warning for conflicting extension numbers.
2153 // TODO(xiaofeng): Change it to an error.
2154 ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
2155 }
2156
2157 // ===================================================================
2158
2159 // Ensure that overlapping extension ranges are not allowed.
TEST(OverlappingExtensionRangeTest,ExtensionRangeInternal)2160 TEST(OverlappingExtensionRangeTest, ExtensionRangeInternal) {
2161 // Build descriptors for the following definitions:
2162 //
2163 // message Foo {
2164 // extensions 10 to 19;
2165 // extensions 15;
2166 // }
2167 FileDescriptorProto foo_file;
2168 foo_file.set_name("foo.proto");
2169
2170 DescriptorProto* foo = AddMessage(&foo_file, "Foo");
2171 AddExtensionRange(foo, 10, 20);
2172 AddExtensionRange(foo, 15, 16);
2173
2174 DescriptorPool pool;
2175 MockErrorCollector error_collector;
2176 // The extensions ranges are invalid, so the proto shouldn't build.
2177 ASSERT_TRUE(pool.BuildFileCollectingErrors(foo_file, &error_collector) ==
2178 nullptr);
2179 ASSERT_EQ(
2180 "foo.proto: Foo: NUMBER: Extension range 15 to 15 overlaps with "
2181 "already-defined range 10 to 19.\n",
2182 error_collector.text_);
2183 }
2184
TEST(OverlappingExtensionRangeTest,ExtensionRangeAfter)2185 TEST(OverlappingExtensionRangeTest, ExtensionRangeAfter) {
2186 // Build descriptors for the following definitions:
2187 //
2188 // message Foo {
2189 // extensions 10 to 19;
2190 // extensions 15 to 24;
2191 // }
2192 FileDescriptorProto foo_file;
2193 foo_file.set_name("foo.proto");
2194
2195 DescriptorProto* foo = AddMessage(&foo_file, "Foo");
2196 AddExtensionRange(foo, 10, 20);
2197 AddExtensionRange(foo, 15, 25);
2198
2199 DescriptorPool pool;
2200 MockErrorCollector error_collector;
2201 // The extensions ranges are invalid, so the proto shouldn't build.
2202 ASSERT_TRUE(pool.BuildFileCollectingErrors(foo_file, &error_collector) ==
2203 nullptr);
2204 ASSERT_EQ(
2205 "foo.proto: Foo: NUMBER: Extension range 15 to 24 overlaps with "
2206 "already-defined range 10 to 19.\n",
2207 error_collector.text_);
2208 }
2209
TEST(OverlappingExtensionRangeTest,ExtensionRangeBefore)2210 TEST(OverlappingExtensionRangeTest, ExtensionRangeBefore) {
2211 // Build descriptors for the following definitions:
2212 //
2213 // message Foo {
2214 // extensions 10 to 19;
2215 // extensions 5 to 14;
2216 // }
2217 FileDescriptorProto foo_file;
2218 foo_file.set_name("foo.proto");
2219
2220 DescriptorProto* foo = AddMessage(&foo_file, "Foo");
2221 AddExtensionRange(foo, 10, 20);
2222 AddExtensionRange(foo, 5, 15);
2223
2224 DescriptorPool pool;
2225 MockErrorCollector error_collector;
2226 // The extensions ranges are invalid, so the proto shouldn't build.
2227 ASSERT_TRUE(pool.BuildFileCollectingErrors(foo_file, &error_collector) ==
2228 nullptr);
2229 ASSERT_EQ(
2230 "foo.proto: Foo: NUMBER: Extension range 5 to 14 overlaps with "
2231 "already-defined range 10 to 19.\n",
2232 error_collector.text_);
2233 }
2234
2235 // ===================================================================
2236
2237 // Test reserved fields.
2238 class ReservedDescriptorTest : public testing::Test {
2239 protected:
SetUp()2240 void SetUp() override {
2241 // Build descriptors for the following definitions:
2242 //
2243 // message Foo {
2244 // reserved 2, 9 to 11, 15;
2245 // reserved "foo", "bar";
2246 // }
2247
2248 FileDescriptorProto foo_file;
2249 foo_file.set_name("foo.proto");
2250
2251 DescriptorProto* foo = AddMessage(&foo_file, "Foo");
2252 AddReservedRange(foo, 2, 3);
2253 AddReservedRange(foo, 9, 12);
2254 AddReservedRange(foo, 15, 16);
2255
2256 foo->add_reserved_name("foo");
2257 foo->add_reserved_name("bar");
2258
2259 // Build the descriptors and get the pointers.
2260 foo_file_ = pool_.BuildFile(foo_file);
2261 ASSERT_TRUE(foo_file_ != nullptr);
2262
2263 ASSERT_EQ(1, foo_file_->message_type_count());
2264 foo_ = foo_file_->message_type(0);
2265 }
2266
2267 DescriptorPool pool_;
2268 const FileDescriptor* foo_file_;
2269 const Descriptor* foo_;
2270 };
2271
TEST_F(ReservedDescriptorTest,ReservedRanges)2272 TEST_F(ReservedDescriptorTest, ReservedRanges) {
2273 ASSERT_EQ(3, foo_->reserved_range_count());
2274
2275 EXPECT_EQ(2, foo_->reserved_range(0)->start);
2276 EXPECT_EQ(3, foo_->reserved_range(0)->end);
2277
2278 EXPECT_EQ(9, foo_->reserved_range(1)->start);
2279 EXPECT_EQ(12, foo_->reserved_range(1)->end);
2280
2281 EXPECT_EQ(15, foo_->reserved_range(2)->start);
2282 EXPECT_EQ(16, foo_->reserved_range(2)->end);
2283 }
2284
TEST_F(ReservedDescriptorTest,IsReservedNumber)2285 TEST_F(ReservedDescriptorTest, IsReservedNumber) {
2286 EXPECT_FALSE(foo_->IsReservedNumber(1));
2287 EXPECT_TRUE(foo_->IsReservedNumber(2));
2288 EXPECT_FALSE(foo_->IsReservedNumber(3));
2289 EXPECT_FALSE(foo_->IsReservedNumber(8));
2290 EXPECT_TRUE(foo_->IsReservedNumber(9));
2291 EXPECT_TRUE(foo_->IsReservedNumber(10));
2292 EXPECT_TRUE(foo_->IsReservedNumber(11));
2293 EXPECT_FALSE(foo_->IsReservedNumber(12));
2294 EXPECT_FALSE(foo_->IsReservedNumber(13));
2295 EXPECT_FALSE(foo_->IsReservedNumber(14));
2296 EXPECT_TRUE(foo_->IsReservedNumber(15));
2297 EXPECT_FALSE(foo_->IsReservedNumber(16));
2298 }
2299
TEST_F(ReservedDescriptorTest,ReservedNames)2300 TEST_F(ReservedDescriptorTest, ReservedNames) {
2301 ASSERT_EQ(2, foo_->reserved_name_count());
2302
2303 EXPECT_EQ("foo", foo_->reserved_name(0));
2304 EXPECT_EQ("bar", foo_->reserved_name(1));
2305 }
2306
TEST_F(ReservedDescriptorTest,IsReservedName)2307 TEST_F(ReservedDescriptorTest, IsReservedName) {
2308 EXPECT_TRUE(foo_->IsReservedName("foo"));
2309 EXPECT_TRUE(foo_->IsReservedName("bar"));
2310 EXPECT_FALSE(foo_->IsReservedName("baz"));
2311 }
2312
2313 // ===================================================================
2314
2315 // Test reserved enum fields.
2316 class ReservedEnumDescriptorTest : public testing::Test {
2317 protected:
SetUp()2318 void SetUp() override {
2319 // Build descriptors for the following definitions:
2320 //
2321 // enum Foo {
2322 // BAR = 1;
2323 // reserved 2, 9 to 11, 15;
2324 // reserved "foo", "bar";
2325 // }
2326
2327 FileDescriptorProto foo_file;
2328 foo_file.set_name("foo.proto");
2329
2330 EnumDescriptorProto* foo = AddEnum(&foo_file, "Foo");
2331 EnumDescriptorProto* edge1 = AddEnum(&foo_file, "Edge1");
2332 EnumDescriptorProto* edge2 = AddEnum(&foo_file, "Edge2");
2333
2334 AddEnumValue(foo, "BAR", 4);
2335 AddReservedRange(foo, -5, -3);
2336 AddReservedRange(foo, -2, 1);
2337 AddReservedRange(foo, 2, 3);
2338 AddReservedRange(foo, 9, 12);
2339 AddReservedRange(foo, 15, 16);
2340
2341 foo->add_reserved_name("foo");
2342 foo->add_reserved_name("bar");
2343
2344 // Some additional edge cases that cover most or all of the range of enum
2345 // values
2346
2347 // Note: We use INT_MAX as the maximum reserved range upper bound,
2348 // inclusive.
2349 AddEnumValue(edge1, "EDGE1", 1);
2350 AddReservedRange(edge1, 10, INT_MAX);
2351 AddEnumValue(edge2, "EDGE2", 15);
2352 AddReservedRange(edge2, INT_MIN, 10);
2353
2354 // Build the descriptors and get the pointers.
2355 foo_file_ = pool_.BuildFile(foo_file);
2356 ASSERT_TRUE(foo_file_ != nullptr);
2357
2358 ASSERT_EQ(3, foo_file_->enum_type_count());
2359 foo_ = foo_file_->enum_type(0);
2360 edge1_ = foo_file_->enum_type(1);
2361 edge2_ = foo_file_->enum_type(2);
2362 }
2363
2364 DescriptorPool pool_;
2365 const FileDescriptor* foo_file_;
2366 const EnumDescriptor* foo_;
2367 const EnumDescriptor* edge1_;
2368 const EnumDescriptor* edge2_;
2369 };
2370
TEST_F(ReservedEnumDescriptorTest,ReservedRanges)2371 TEST_F(ReservedEnumDescriptorTest, ReservedRanges) {
2372 ASSERT_EQ(5, foo_->reserved_range_count());
2373
2374 EXPECT_EQ(-5, foo_->reserved_range(0)->start);
2375 EXPECT_EQ(-3, foo_->reserved_range(0)->end);
2376
2377 EXPECT_EQ(-2, foo_->reserved_range(1)->start);
2378 EXPECT_EQ(1, foo_->reserved_range(1)->end);
2379
2380 EXPECT_EQ(2, foo_->reserved_range(2)->start);
2381 EXPECT_EQ(3, foo_->reserved_range(2)->end);
2382
2383 EXPECT_EQ(9, foo_->reserved_range(3)->start);
2384 EXPECT_EQ(12, foo_->reserved_range(3)->end);
2385
2386 EXPECT_EQ(15, foo_->reserved_range(4)->start);
2387 EXPECT_EQ(16, foo_->reserved_range(4)->end);
2388
2389 ASSERT_EQ(1, edge1_->reserved_range_count());
2390 EXPECT_EQ(10, edge1_->reserved_range(0)->start);
2391 EXPECT_EQ(INT_MAX, edge1_->reserved_range(0)->end);
2392
2393 ASSERT_EQ(1, edge2_->reserved_range_count());
2394 EXPECT_EQ(INT_MIN, edge2_->reserved_range(0)->start);
2395 EXPECT_EQ(10, edge2_->reserved_range(0)->end);
2396 }
2397
TEST_F(ReservedEnumDescriptorTest,IsReservedNumber)2398 TEST_F(ReservedEnumDescriptorTest, IsReservedNumber) {
2399 EXPECT_TRUE(foo_->IsReservedNumber(-5));
2400 EXPECT_TRUE(foo_->IsReservedNumber(-4));
2401 EXPECT_TRUE(foo_->IsReservedNumber(-3));
2402 EXPECT_TRUE(foo_->IsReservedNumber(-2));
2403 EXPECT_TRUE(foo_->IsReservedNumber(-1));
2404 EXPECT_TRUE(foo_->IsReservedNumber(0));
2405 EXPECT_TRUE(foo_->IsReservedNumber(1));
2406 EXPECT_TRUE(foo_->IsReservedNumber(2));
2407 EXPECT_TRUE(foo_->IsReservedNumber(3));
2408 EXPECT_FALSE(foo_->IsReservedNumber(8));
2409 EXPECT_TRUE(foo_->IsReservedNumber(9));
2410 EXPECT_TRUE(foo_->IsReservedNumber(10));
2411 EXPECT_TRUE(foo_->IsReservedNumber(11));
2412 EXPECT_TRUE(foo_->IsReservedNumber(12));
2413 EXPECT_FALSE(foo_->IsReservedNumber(13));
2414 EXPECT_FALSE(foo_->IsReservedNumber(13));
2415 EXPECT_FALSE(foo_->IsReservedNumber(14));
2416 EXPECT_TRUE(foo_->IsReservedNumber(15));
2417 EXPECT_TRUE(foo_->IsReservedNumber(16));
2418 EXPECT_FALSE(foo_->IsReservedNumber(17));
2419
2420 EXPECT_FALSE(edge1_->IsReservedNumber(9));
2421 EXPECT_TRUE(edge1_->IsReservedNumber(10));
2422 EXPECT_TRUE(edge1_->IsReservedNumber(INT_MAX - 1));
2423 EXPECT_TRUE(edge1_->IsReservedNumber(INT_MAX));
2424
2425 EXPECT_TRUE(edge2_->IsReservedNumber(INT_MIN));
2426 EXPECT_TRUE(edge2_->IsReservedNumber(9));
2427 EXPECT_TRUE(edge2_->IsReservedNumber(10));
2428 EXPECT_FALSE(edge2_->IsReservedNumber(11));
2429 }
2430
TEST_F(ReservedEnumDescriptorTest,ReservedNames)2431 TEST_F(ReservedEnumDescriptorTest, ReservedNames) {
2432 ASSERT_EQ(2, foo_->reserved_name_count());
2433
2434 EXPECT_EQ("foo", foo_->reserved_name(0));
2435 EXPECT_EQ("bar", foo_->reserved_name(1));
2436 }
2437
TEST_F(ReservedEnumDescriptorTest,IsReservedName)2438 TEST_F(ReservedEnumDescriptorTest, IsReservedName) {
2439 EXPECT_TRUE(foo_->IsReservedName("foo"));
2440 EXPECT_TRUE(foo_->IsReservedName("bar"));
2441 EXPECT_FALSE(foo_->IsReservedName("baz"));
2442 }
2443
2444 // ===================================================================
2445
2446 class MiscTest : public testing::Test {
2447 protected:
2448 // Function which makes a field descriptor of the given type.
GetFieldDescriptorOfType(FieldDescriptor::Type type)2449 const FieldDescriptor* GetFieldDescriptorOfType(FieldDescriptor::Type type) {
2450 FileDescriptorProto file_proto;
2451 file_proto.set_name("foo.proto");
2452 AddEmptyEnum(&file_proto, "DummyEnum");
2453
2454 DescriptorProto* message = AddMessage(&file_proto, "TestMessage");
2455 FieldDescriptorProto* field = AddField(
2456 message, "foo", 1, FieldDescriptorProto::LABEL_OPTIONAL,
2457 static_cast<FieldDescriptorProto::Type>(static_cast<int>(type)));
2458
2459 if (type == FieldDescriptor::TYPE_MESSAGE ||
2460 type == FieldDescriptor::TYPE_GROUP) {
2461 field->set_type_name("TestMessage");
2462 } else if (type == FieldDescriptor::TYPE_ENUM) {
2463 field->set_type_name("DummyEnum");
2464 }
2465
2466 // Build the descriptors and get the pointers.
2467 pool_.reset(new DescriptorPool());
2468 const FileDescriptor* file = pool_->BuildFile(file_proto);
2469
2470 if (file != nullptr && file->message_type_count() == 1 &&
2471 file->message_type(0)->field_count() == 1) {
2472 return file->message_type(0)->field(0);
2473 } else {
2474 return nullptr;
2475 }
2476 }
2477
GetTypeNameForFieldType(FieldDescriptor::Type type)2478 const char* GetTypeNameForFieldType(FieldDescriptor::Type type) {
2479 const FieldDescriptor* field = GetFieldDescriptorOfType(type);
2480 return field != nullptr ? field->type_name() : "";
2481 }
2482
GetCppTypeForFieldType(FieldDescriptor::Type type)2483 FieldDescriptor::CppType GetCppTypeForFieldType(FieldDescriptor::Type type) {
2484 const FieldDescriptor* field = GetFieldDescriptorOfType(type);
2485 return field != nullptr ? field->cpp_type()
2486 : static_cast<FieldDescriptor::CppType>(0);
2487 }
2488
GetCppTypeNameForFieldType(FieldDescriptor::Type type)2489 const char* GetCppTypeNameForFieldType(FieldDescriptor::Type type) {
2490 const FieldDescriptor* field = GetFieldDescriptorOfType(type);
2491 return field != nullptr ? field->cpp_type_name() : "";
2492 }
2493
GetMessageDescriptorForFieldType(FieldDescriptor::Type type)2494 const Descriptor* GetMessageDescriptorForFieldType(
2495 FieldDescriptor::Type type) {
2496 const FieldDescriptor* field = GetFieldDescriptorOfType(type);
2497 return field != nullptr ? field->message_type() : nullptr;
2498 }
2499
GetEnumDescriptorForFieldType(FieldDescriptor::Type type)2500 const EnumDescriptor* GetEnumDescriptorForFieldType(
2501 FieldDescriptor::Type type) {
2502 const FieldDescriptor* field = GetFieldDescriptorOfType(type);
2503 return field != nullptr ? field->enum_type() : nullptr;
2504 }
2505
2506 std::unique_ptr<DescriptorPool> pool_;
2507 };
2508
TEST_F(MiscTest,TypeNames)2509 TEST_F(MiscTest, TypeNames) {
2510 // Test that correct type names are returned.
2511
2512 typedef FieldDescriptor FD; // avoid ugly line wrapping
2513
2514 EXPECT_STREQ("double", GetTypeNameForFieldType(FD::TYPE_DOUBLE));
2515 EXPECT_STREQ("float", GetTypeNameForFieldType(FD::TYPE_FLOAT));
2516 EXPECT_STREQ("int64", GetTypeNameForFieldType(FD::TYPE_INT64));
2517 EXPECT_STREQ("uint64", GetTypeNameForFieldType(FD::TYPE_UINT64));
2518 EXPECT_STREQ("int32", GetTypeNameForFieldType(FD::TYPE_INT32));
2519 EXPECT_STREQ("fixed64", GetTypeNameForFieldType(FD::TYPE_FIXED64));
2520 EXPECT_STREQ("fixed32", GetTypeNameForFieldType(FD::TYPE_FIXED32));
2521 EXPECT_STREQ("bool", GetTypeNameForFieldType(FD::TYPE_BOOL));
2522 EXPECT_STREQ("string", GetTypeNameForFieldType(FD::TYPE_STRING));
2523 EXPECT_STREQ("group", GetTypeNameForFieldType(FD::TYPE_GROUP));
2524 EXPECT_STREQ("message", GetTypeNameForFieldType(FD::TYPE_MESSAGE));
2525 EXPECT_STREQ("bytes", GetTypeNameForFieldType(FD::TYPE_BYTES));
2526 EXPECT_STREQ("uint32", GetTypeNameForFieldType(FD::TYPE_UINT32));
2527 EXPECT_STREQ("enum", GetTypeNameForFieldType(FD::TYPE_ENUM));
2528 EXPECT_STREQ("sfixed32", GetTypeNameForFieldType(FD::TYPE_SFIXED32));
2529 EXPECT_STREQ("sfixed64", GetTypeNameForFieldType(FD::TYPE_SFIXED64));
2530 EXPECT_STREQ("sint32", GetTypeNameForFieldType(FD::TYPE_SINT32));
2531 EXPECT_STREQ("sint64", GetTypeNameForFieldType(FD::TYPE_SINT64));
2532 }
2533
TEST_F(MiscTest,StaticTypeNames)2534 TEST_F(MiscTest, StaticTypeNames) {
2535 // Test that correct type names are returned.
2536
2537 typedef FieldDescriptor FD; // avoid ugly line wrapping
2538
2539 EXPECT_STREQ("double", FD::TypeName(FD::TYPE_DOUBLE));
2540 EXPECT_STREQ("float", FD::TypeName(FD::TYPE_FLOAT));
2541 EXPECT_STREQ("int64", FD::TypeName(FD::TYPE_INT64));
2542 EXPECT_STREQ("uint64", FD::TypeName(FD::TYPE_UINT64));
2543 EXPECT_STREQ("int32", FD::TypeName(FD::TYPE_INT32));
2544 EXPECT_STREQ("fixed64", FD::TypeName(FD::TYPE_FIXED64));
2545 EXPECT_STREQ("fixed32", FD::TypeName(FD::TYPE_FIXED32));
2546 EXPECT_STREQ("bool", FD::TypeName(FD::TYPE_BOOL));
2547 EXPECT_STREQ("string", FD::TypeName(FD::TYPE_STRING));
2548 EXPECT_STREQ("group", FD::TypeName(FD::TYPE_GROUP));
2549 EXPECT_STREQ("message", FD::TypeName(FD::TYPE_MESSAGE));
2550 EXPECT_STREQ("bytes", FD::TypeName(FD::TYPE_BYTES));
2551 EXPECT_STREQ("uint32", FD::TypeName(FD::TYPE_UINT32));
2552 EXPECT_STREQ("enum", FD::TypeName(FD::TYPE_ENUM));
2553 EXPECT_STREQ("sfixed32", FD::TypeName(FD::TYPE_SFIXED32));
2554 EXPECT_STREQ("sfixed64", FD::TypeName(FD::TYPE_SFIXED64));
2555 EXPECT_STREQ("sint32", FD::TypeName(FD::TYPE_SINT32));
2556 EXPECT_STREQ("sint64", FD::TypeName(FD::TYPE_SINT64));
2557 }
2558
TEST_F(MiscTest,CppTypes)2559 TEST_F(MiscTest, CppTypes) {
2560 // Test that CPP types are assigned correctly.
2561
2562 typedef FieldDescriptor FD; // avoid ugly line wrapping
2563
2564 EXPECT_EQ(FD::CPPTYPE_DOUBLE, GetCppTypeForFieldType(FD::TYPE_DOUBLE));
2565 EXPECT_EQ(FD::CPPTYPE_FLOAT, GetCppTypeForFieldType(FD::TYPE_FLOAT));
2566 EXPECT_EQ(FD::CPPTYPE_INT64, GetCppTypeForFieldType(FD::TYPE_INT64));
2567 EXPECT_EQ(FD::CPPTYPE_UINT64, GetCppTypeForFieldType(FD::TYPE_UINT64));
2568 EXPECT_EQ(FD::CPPTYPE_INT32, GetCppTypeForFieldType(FD::TYPE_INT32));
2569 EXPECT_EQ(FD::CPPTYPE_UINT64, GetCppTypeForFieldType(FD::TYPE_FIXED64));
2570 EXPECT_EQ(FD::CPPTYPE_UINT32, GetCppTypeForFieldType(FD::TYPE_FIXED32));
2571 EXPECT_EQ(FD::CPPTYPE_BOOL, GetCppTypeForFieldType(FD::TYPE_BOOL));
2572 EXPECT_EQ(FD::CPPTYPE_STRING, GetCppTypeForFieldType(FD::TYPE_STRING));
2573 EXPECT_EQ(FD::CPPTYPE_MESSAGE, GetCppTypeForFieldType(FD::TYPE_GROUP));
2574 EXPECT_EQ(FD::CPPTYPE_MESSAGE, GetCppTypeForFieldType(FD::TYPE_MESSAGE));
2575 EXPECT_EQ(FD::CPPTYPE_STRING, GetCppTypeForFieldType(FD::TYPE_BYTES));
2576 EXPECT_EQ(FD::CPPTYPE_UINT32, GetCppTypeForFieldType(FD::TYPE_UINT32));
2577 EXPECT_EQ(FD::CPPTYPE_ENUM, GetCppTypeForFieldType(FD::TYPE_ENUM));
2578 EXPECT_EQ(FD::CPPTYPE_INT32, GetCppTypeForFieldType(FD::TYPE_SFIXED32));
2579 EXPECT_EQ(FD::CPPTYPE_INT64, GetCppTypeForFieldType(FD::TYPE_SFIXED64));
2580 EXPECT_EQ(FD::CPPTYPE_INT32, GetCppTypeForFieldType(FD::TYPE_SINT32));
2581 EXPECT_EQ(FD::CPPTYPE_INT64, GetCppTypeForFieldType(FD::TYPE_SINT64));
2582 }
2583
TEST_F(MiscTest,CppTypeNames)2584 TEST_F(MiscTest, CppTypeNames) {
2585 // Test that correct CPP type names are returned.
2586
2587 typedef FieldDescriptor FD; // avoid ugly line wrapping
2588
2589 EXPECT_STREQ("double", GetCppTypeNameForFieldType(FD::TYPE_DOUBLE));
2590 EXPECT_STREQ("float", GetCppTypeNameForFieldType(FD::TYPE_FLOAT));
2591 EXPECT_STREQ("int64", GetCppTypeNameForFieldType(FD::TYPE_INT64));
2592 EXPECT_STREQ("uint64", GetCppTypeNameForFieldType(FD::TYPE_UINT64));
2593 EXPECT_STREQ("int32", GetCppTypeNameForFieldType(FD::TYPE_INT32));
2594 EXPECT_STREQ("uint64", GetCppTypeNameForFieldType(FD::TYPE_FIXED64));
2595 EXPECT_STREQ("uint32", GetCppTypeNameForFieldType(FD::TYPE_FIXED32));
2596 EXPECT_STREQ("bool", GetCppTypeNameForFieldType(FD::TYPE_BOOL));
2597 EXPECT_STREQ("string", GetCppTypeNameForFieldType(FD::TYPE_STRING));
2598 EXPECT_STREQ("message", GetCppTypeNameForFieldType(FD::TYPE_GROUP));
2599 EXPECT_STREQ("message", GetCppTypeNameForFieldType(FD::TYPE_MESSAGE));
2600 EXPECT_STREQ("string", GetCppTypeNameForFieldType(FD::TYPE_BYTES));
2601 EXPECT_STREQ("uint32", GetCppTypeNameForFieldType(FD::TYPE_UINT32));
2602 EXPECT_STREQ("enum", GetCppTypeNameForFieldType(FD::TYPE_ENUM));
2603 EXPECT_STREQ("int32", GetCppTypeNameForFieldType(FD::TYPE_SFIXED32));
2604 EXPECT_STREQ("int64", GetCppTypeNameForFieldType(FD::TYPE_SFIXED64));
2605 EXPECT_STREQ("int32", GetCppTypeNameForFieldType(FD::TYPE_SINT32));
2606 EXPECT_STREQ("int64", GetCppTypeNameForFieldType(FD::TYPE_SINT64));
2607 }
2608
TEST_F(MiscTest,StaticCppTypeNames)2609 TEST_F(MiscTest, StaticCppTypeNames) {
2610 // Test that correct CPP type names are returned.
2611
2612 typedef FieldDescriptor FD; // avoid ugly line wrapping
2613
2614 EXPECT_STREQ("int32", FD::CppTypeName(FD::CPPTYPE_INT32));
2615 EXPECT_STREQ("int64", FD::CppTypeName(FD::CPPTYPE_INT64));
2616 EXPECT_STREQ("uint32", FD::CppTypeName(FD::CPPTYPE_UINT32));
2617 EXPECT_STREQ("uint64", FD::CppTypeName(FD::CPPTYPE_UINT64));
2618 EXPECT_STREQ("double", FD::CppTypeName(FD::CPPTYPE_DOUBLE));
2619 EXPECT_STREQ("float", FD::CppTypeName(FD::CPPTYPE_FLOAT));
2620 EXPECT_STREQ("bool", FD::CppTypeName(FD::CPPTYPE_BOOL));
2621 EXPECT_STREQ("enum", FD::CppTypeName(FD::CPPTYPE_ENUM));
2622 EXPECT_STREQ("string", FD::CppTypeName(FD::CPPTYPE_STRING));
2623 EXPECT_STREQ("message", FD::CppTypeName(FD::CPPTYPE_MESSAGE));
2624 }
2625
TEST_F(MiscTest,MessageType)2626 TEST_F(MiscTest, MessageType) {
2627 // Test that message_type() is nullptr for non-aggregate fields
2628
2629 typedef FieldDescriptor FD; // avoid ugly line wrapping
2630
2631 EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_DOUBLE));
2632 EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_FLOAT));
2633 EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_INT64));
2634 EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_UINT64));
2635 EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_INT32));
2636 EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_FIXED64));
2637 EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_FIXED32));
2638 EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_BOOL));
2639 EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_STRING));
2640 EXPECT_TRUE(nullptr != GetMessageDescriptorForFieldType(FD::TYPE_GROUP));
2641 EXPECT_TRUE(nullptr != GetMessageDescriptorForFieldType(FD::TYPE_MESSAGE));
2642 EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_BYTES));
2643 EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_UINT32));
2644 EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_ENUM));
2645 EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_SFIXED32));
2646 EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_SFIXED64));
2647 EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_SINT32));
2648 EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_SINT64));
2649 }
2650
TEST_F(MiscTest,EnumType)2651 TEST_F(MiscTest, EnumType) {
2652 // Test that enum_type() is nullptr for non-enum fields
2653
2654 typedef FieldDescriptor FD; // avoid ugly line wrapping
2655
2656 EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_DOUBLE));
2657 EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_FLOAT));
2658 EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_INT64));
2659 EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_UINT64));
2660 EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_INT32));
2661 EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_FIXED64));
2662 EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_FIXED32));
2663 EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_BOOL));
2664 EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_STRING));
2665 EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_GROUP));
2666 EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_MESSAGE));
2667 EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_BYTES));
2668 EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_UINT32));
2669 EXPECT_TRUE(nullptr != GetEnumDescriptorForFieldType(FD::TYPE_ENUM));
2670 EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_SFIXED32));
2671 EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_SFIXED64));
2672 EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_SINT32));
2673 EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_SINT64));
2674 }
2675
TEST_F(MiscTest,DefaultValues)2676 TEST_F(MiscTest, DefaultValues) {
2677 // Test that setting default values works.
2678 FileDescriptorProto file_proto;
2679 file_proto.set_name("foo.proto");
2680
2681 EnumDescriptorProto* enum_type_proto = AddEnum(&file_proto, "DummyEnum");
2682 AddEnumValue(enum_type_proto, "A", 1);
2683 AddEnumValue(enum_type_proto, "B", 2);
2684
2685 DescriptorProto* message_proto = AddMessage(&file_proto, "TestMessage");
2686
2687 typedef FieldDescriptorProto FD; // avoid ugly line wrapping
2688 const FD::Label label = FD::LABEL_OPTIONAL;
2689
2690 // Create fields of every CPP type with default values.
2691 AddField(message_proto, "int32", 1, label, FD::TYPE_INT32)
2692 ->set_default_value("-1");
2693 AddField(message_proto, "int64", 2, label, FD::TYPE_INT64)
2694 ->set_default_value("-1000000000000");
2695 AddField(message_proto, "uint32", 3, label, FD::TYPE_UINT32)
2696 ->set_default_value("42");
2697 AddField(message_proto, "uint64", 4, label, FD::TYPE_UINT64)
2698 ->set_default_value("2000000000000");
2699 AddField(message_proto, "float", 5, label, FD::TYPE_FLOAT)
2700 ->set_default_value("4.5");
2701 AddField(message_proto, "double", 6, label, FD::TYPE_DOUBLE)
2702 ->set_default_value("10e100");
2703 AddField(message_proto, "bool", 7, label, FD::TYPE_BOOL)
2704 ->set_default_value("true");
2705 AddField(message_proto, "string", 8, label, FD::TYPE_STRING)
2706 ->set_default_value("hello");
2707 AddField(message_proto, "data", 9, label, FD::TYPE_BYTES)
2708 ->set_default_value("\\001\\002\\003");
2709
2710 FieldDescriptorProto* enum_field =
2711 AddField(message_proto, "enum", 10, label, FD::TYPE_ENUM);
2712 enum_field->set_type_name("DummyEnum");
2713 enum_field->set_default_value("B");
2714
2715 // Strings are allowed to have empty defaults. (At one point, due to
2716 // a bug, empty defaults for strings were rejected. Oops.)
2717 AddField(message_proto, "empty_string", 11, label, FD::TYPE_STRING)
2718 ->set_default_value("");
2719
2720 // Add a second set of fields with implicit default values.
2721 AddField(message_proto, "implicit_int32", 21, label, FD::TYPE_INT32);
2722 AddField(message_proto, "implicit_int64", 22, label, FD::TYPE_INT64);
2723 AddField(message_proto, "implicit_uint32", 23, label, FD::TYPE_UINT32);
2724 AddField(message_proto, "implicit_uint64", 24, label, FD::TYPE_UINT64);
2725 AddField(message_proto, "implicit_float", 25, label, FD::TYPE_FLOAT);
2726 AddField(message_proto, "implicit_double", 26, label, FD::TYPE_DOUBLE);
2727 AddField(message_proto, "implicit_bool", 27, label, FD::TYPE_BOOL);
2728 AddField(message_proto, "implicit_string", 28, label, FD::TYPE_STRING);
2729 AddField(message_proto, "implicit_data", 29, label, FD::TYPE_BYTES);
2730 AddField(message_proto, "implicit_enum", 30, label, FD::TYPE_ENUM)
2731 ->set_type_name("DummyEnum");
2732
2733 // Build it.
2734 DescriptorPool pool;
2735 const FileDescriptor* file = pool.BuildFile(file_proto);
2736 ASSERT_TRUE(file != nullptr);
2737
2738 ASSERT_EQ(1, file->enum_type_count());
2739 const EnumDescriptor* enum_type = file->enum_type(0);
2740 ASSERT_EQ(2, enum_type->value_count());
2741 const EnumValueDescriptor* enum_value_a = enum_type->value(0);
2742 const EnumValueDescriptor* enum_value_b = enum_type->value(1);
2743
2744 ASSERT_EQ(1, file->message_type_count());
2745 const Descriptor* message = file->message_type(0);
2746
2747 ASSERT_EQ(21, message->field_count());
2748
2749 // Check the default values.
2750 ASSERT_TRUE(message->field(0)->has_default_value());
2751 ASSERT_TRUE(message->field(1)->has_default_value());
2752 ASSERT_TRUE(message->field(2)->has_default_value());
2753 ASSERT_TRUE(message->field(3)->has_default_value());
2754 ASSERT_TRUE(message->field(4)->has_default_value());
2755 ASSERT_TRUE(message->field(5)->has_default_value());
2756 ASSERT_TRUE(message->field(6)->has_default_value());
2757 ASSERT_TRUE(message->field(7)->has_default_value());
2758 ASSERT_TRUE(message->field(8)->has_default_value());
2759 ASSERT_TRUE(message->field(9)->has_default_value());
2760 ASSERT_TRUE(message->field(10)->has_default_value());
2761
2762 EXPECT_EQ(-1, message->field(0)->default_value_int32());
2763 EXPECT_EQ(int64_t{-1000000000000}, message->field(1)->default_value_int64());
2764 EXPECT_EQ(42, message->field(2)->default_value_uint32());
2765 EXPECT_EQ(uint64_t{2000000000000}, message->field(3)->default_value_uint64());
2766 EXPECT_EQ(4.5, message->field(4)->default_value_float());
2767 EXPECT_EQ(10e100, message->field(5)->default_value_double());
2768 EXPECT_TRUE(message->field(6)->default_value_bool());
2769 EXPECT_EQ("hello", message->field(7)->default_value_string());
2770 EXPECT_EQ("\001\002\003", message->field(8)->default_value_string());
2771 EXPECT_EQ(enum_value_b, message->field(9)->default_value_enum());
2772 EXPECT_EQ("", message->field(10)->default_value_string());
2773
2774 ASSERT_FALSE(message->field(11)->has_default_value());
2775 ASSERT_FALSE(message->field(12)->has_default_value());
2776 ASSERT_FALSE(message->field(13)->has_default_value());
2777 ASSERT_FALSE(message->field(14)->has_default_value());
2778 ASSERT_FALSE(message->field(15)->has_default_value());
2779 ASSERT_FALSE(message->field(16)->has_default_value());
2780 ASSERT_FALSE(message->field(17)->has_default_value());
2781 ASSERT_FALSE(message->field(18)->has_default_value());
2782 ASSERT_FALSE(message->field(19)->has_default_value());
2783 ASSERT_FALSE(message->field(20)->has_default_value());
2784
2785 EXPECT_EQ(0, message->field(11)->default_value_int32());
2786 EXPECT_EQ(0, message->field(12)->default_value_int64());
2787 EXPECT_EQ(0, message->field(13)->default_value_uint32());
2788 EXPECT_EQ(0, message->field(14)->default_value_uint64());
2789 EXPECT_EQ(0.0f, message->field(15)->default_value_float());
2790 EXPECT_EQ(0.0, message->field(16)->default_value_double());
2791 EXPECT_FALSE(message->field(17)->default_value_bool());
2792 EXPECT_EQ("", message->field(18)->default_value_string());
2793 EXPECT_EQ("", message->field(19)->default_value_string());
2794 EXPECT_EQ(enum_value_a, message->field(20)->default_value_enum());
2795 }
2796
TEST_F(MiscTest,FieldOptions)2797 TEST_F(MiscTest, FieldOptions) {
2798 // Try setting field options.
2799
2800 FileDescriptorProto file_proto;
2801 file_proto.set_name("foo.proto");
2802
2803 DescriptorProto* message_proto = AddMessage(&file_proto, "TestMessage");
2804 AddField(message_proto, "foo", 1, FieldDescriptorProto::LABEL_OPTIONAL,
2805 FieldDescriptorProto::TYPE_INT32);
2806 FieldDescriptorProto* bar_proto =
2807 AddField(message_proto, "bar", 2, FieldDescriptorProto::LABEL_OPTIONAL,
2808 FieldDescriptorProto::TYPE_INT32);
2809
2810 FieldOptions* options = bar_proto->mutable_options();
2811 options->set_ctype(FieldOptions::CORD);
2812
2813 // Build the descriptors and get the pointers.
2814 DescriptorPool pool;
2815 const FileDescriptor* file = pool.BuildFile(file_proto);
2816 ASSERT_TRUE(file != nullptr);
2817
2818 ASSERT_EQ(1, file->message_type_count());
2819 const Descriptor* message = file->message_type(0);
2820
2821 ASSERT_EQ(2, message->field_count());
2822 const FieldDescriptor* foo = message->field(0);
2823 const FieldDescriptor* bar = message->field(1);
2824
2825 // "foo" had no options set, so it should return the default options.
2826 EXPECT_EQ(&FieldOptions::default_instance(), &foo->options());
2827
2828 // "bar" had options set.
2829 EXPECT_NE(&FieldOptions::default_instance(), options);
2830 EXPECT_TRUE(bar->options().has_ctype());
2831 EXPECT_EQ(FieldOptions::CORD, bar->options().ctype());
2832 }
2833
2834 // ===================================================================
2835 enum DescriptorPoolMode { NO_DATABASE, FALLBACK_DATABASE };
2836
2837 class AllowUnknownDependenciesTest
2838 : public testing::TestWithParam<
2839 std::tuple<DescriptorPoolMode, const char*>> {
2840 protected:
mode()2841 DescriptorPoolMode mode() { return std::get<0>(GetParam()); }
syntax()2842 const char* syntax() { return std::get<1>(GetParam()); }
2843
SetUp()2844 void SetUp() override {
2845 FileDescriptorProto foo_proto, bar_proto;
2846
2847 switch (mode()) {
2848 case NO_DATABASE:
2849 pool_.reset(new DescriptorPool);
2850 break;
2851 case FALLBACK_DATABASE:
2852 pool_.reset(new DescriptorPool(&db_));
2853 break;
2854 }
2855
2856 pool_->AllowUnknownDependencies();
2857
2858 ASSERT_TRUE(TextFormat::ParseFromString(
2859 "name: 'foo.proto'"
2860 "dependency: 'bar.proto'"
2861 "dependency: 'baz.proto'"
2862 "message_type {"
2863 " name: 'Foo'"
2864 " field { name:'bar' number:1 label:LABEL_OPTIONAL type_name:'Bar' }"
2865 " field { name:'baz' number:2 label:LABEL_OPTIONAL type_name:'Baz' }"
2866 " field { name:'qux' number:3 label:LABEL_OPTIONAL"
2867 " type_name: '.corge.Qux'"
2868 " type: TYPE_ENUM"
2869 " options {"
2870 " uninterpreted_option {"
2871 " name {"
2872 " name_part: 'grault'"
2873 " is_extension: true"
2874 " }"
2875 " positive_int_value: 1234"
2876 " }"
2877 " }"
2878 " }"
2879 "}",
2880 &foo_proto));
2881 foo_proto.set_syntax(syntax());
2882
2883 ASSERT_TRUE(
2884 TextFormat::ParseFromString("name: 'bar.proto'"
2885 "message_type { name: 'Bar' }",
2886 &bar_proto));
2887 bar_proto.set_syntax(syntax());
2888
2889 // Collect pointers to stuff.
2890 bar_file_ = BuildFile(bar_proto);
2891 ASSERT_TRUE(bar_file_ != nullptr);
2892
2893 ASSERT_EQ(1, bar_file_->message_type_count());
2894 bar_type_ = bar_file_->message_type(0);
2895
2896 foo_file_ = BuildFile(foo_proto);
2897 ASSERT_TRUE(foo_file_ != nullptr);
2898
2899 ASSERT_EQ(1, foo_file_->message_type_count());
2900 foo_type_ = foo_file_->message_type(0);
2901
2902 ASSERT_EQ(3, foo_type_->field_count());
2903 bar_field_ = foo_type_->field(0);
2904 baz_field_ = foo_type_->field(1);
2905 qux_field_ = foo_type_->field(2);
2906 }
2907
BuildFile(const FileDescriptorProto & proto)2908 const FileDescriptor* BuildFile(const FileDescriptorProto& proto) {
2909 switch (mode()) {
2910 case NO_DATABASE:
2911 return pool_->BuildFile(proto);
2912 break;
2913 case FALLBACK_DATABASE: {
2914 EXPECT_TRUE(db_.Add(proto));
2915 return pool_->FindFileByName(proto.name());
2916 }
2917 }
2918 GOOGLE_LOG(FATAL) << "Can't get here.";
2919 return nullptr;
2920 }
2921
2922 const FileDescriptor* bar_file_;
2923 const Descriptor* bar_type_;
2924 const FileDescriptor* foo_file_;
2925 const Descriptor* foo_type_;
2926 const FieldDescriptor* bar_field_;
2927 const FieldDescriptor* baz_field_;
2928 const FieldDescriptor* qux_field_;
2929
2930 SimpleDescriptorDatabase db_; // used if in FALLBACK_DATABASE mode.
2931 std::unique_ptr<DescriptorPool> pool_;
2932 };
2933
TEST_P(AllowUnknownDependenciesTest,PlaceholderFile)2934 TEST_P(AllowUnknownDependenciesTest, PlaceholderFile) {
2935 ASSERT_EQ(2, foo_file_->dependency_count());
2936 EXPECT_EQ(bar_file_, foo_file_->dependency(0));
2937 EXPECT_FALSE(bar_file_->is_placeholder());
2938
2939 const FileDescriptor* baz_file = foo_file_->dependency(1);
2940 EXPECT_EQ("baz.proto", baz_file->name());
2941 EXPECT_EQ(0, baz_file->message_type_count());
2942 EXPECT_TRUE(baz_file->is_placeholder());
2943
2944 // Placeholder files should not be findable.
2945 EXPECT_EQ(bar_file_, pool_->FindFileByName(bar_file_->name()));
2946 EXPECT_TRUE(pool_->FindFileByName(baz_file->name()) == nullptr);
2947
2948 // Copy*To should not crash for placeholder files.
2949 FileDescriptorProto baz_file_proto;
2950 baz_file->CopyTo(&baz_file_proto);
2951 baz_file->CopySourceCodeInfoTo(&baz_file_proto);
2952 EXPECT_FALSE(baz_file_proto.has_source_code_info());
2953 }
2954
TEST_P(AllowUnknownDependenciesTest,PlaceholderTypes)2955 TEST_P(AllowUnknownDependenciesTest, PlaceholderTypes) {
2956 ASSERT_EQ(FieldDescriptor::TYPE_MESSAGE, bar_field_->type());
2957 EXPECT_EQ(bar_type_, bar_field_->message_type());
2958 EXPECT_FALSE(bar_type_->is_placeholder());
2959
2960 ASSERT_EQ(FieldDescriptor::TYPE_MESSAGE, baz_field_->type());
2961 const Descriptor* baz_type = baz_field_->message_type();
2962 EXPECT_EQ("Baz", baz_type->name());
2963 EXPECT_EQ("Baz", baz_type->full_name());
2964 EXPECT_EQ(0, baz_type->extension_range_count());
2965 EXPECT_TRUE(baz_type->is_placeholder());
2966
2967 ASSERT_EQ(FieldDescriptor::TYPE_ENUM, qux_field_->type());
2968 const EnumDescriptor* qux_type = qux_field_->enum_type();
2969 EXPECT_EQ("Qux", qux_type->name());
2970 EXPECT_EQ("corge.Qux", qux_type->full_name());
2971 EXPECT_TRUE(qux_type->is_placeholder());
2972 // Placeholder enum values should not be findable.
2973 EXPECT_EQ(qux_type->FindValueByNumber(0), nullptr);
2974
2975 // Placeholder types should not be findable.
2976 EXPECT_EQ(bar_type_, pool_->FindMessageTypeByName(bar_type_->full_name()));
2977 EXPECT_TRUE(pool_->FindMessageTypeByName(baz_type->full_name()) == nullptr);
2978 EXPECT_TRUE(pool_->FindEnumTypeByName(qux_type->full_name()) == nullptr);
2979 }
2980
TEST_P(AllowUnknownDependenciesTest,CopyTo)2981 TEST_P(AllowUnknownDependenciesTest, CopyTo) {
2982 // FieldDescriptor::CopyTo() should write non-fully-qualified type names
2983 // for placeholder types which were not originally fully-qualified.
2984 FieldDescriptorProto proto;
2985
2986 // Bar is not a placeholder, so it is fully-qualified.
2987 bar_field_->CopyTo(&proto);
2988 EXPECT_EQ(".Bar", proto.type_name());
2989 EXPECT_EQ(FieldDescriptorProto::TYPE_MESSAGE, proto.type());
2990
2991 // Baz is an unqualified placeholder.
2992 proto.Clear();
2993 baz_field_->CopyTo(&proto);
2994 EXPECT_EQ("Baz", proto.type_name());
2995 EXPECT_FALSE(proto.has_type());
2996
2997 // Qux is a fully-qualified placeholder.
2998 proto.Clear();
2999 qux_field_->CopyTo(&proto);
3000 EXPECT_EQ(".corge.Qux", proto.type_name());
3001 EXPECT_EQ(FieldDescriptorProto::TYPE_ENUM, proto.type());
3002 }
3003
TEST_P(AllowUnknownDependenciesTest,CustomOptions)3004 TEST_P(AllowUnknownDependenciesTest, CustomOptions) {
3005 // Qux should still have the uninterpreted option attached.
3006 ASSERT_EQ(1, qux_field_->options().uninterpreted_option_size());
3007 const UninterpretedOption& option =
3008 qux_field_->options().uninterpreted_option(0);
3009 ASSERT_EQ(1, option.name_size());
3010 EXPECT_EQ("grault", option.name(0).name_part());
3011 }
3012
TEST_P(AllowUnknownDependenciesTest,UnknownExtendee)3013 TEST_P(AllowUnknownDependenciesTest, UnknownExtendee) {
3014 // Test that we can extend an unknown type. This is slightly tricky because
3015 // it means that the placeholder type must have an extension range.
3016
3017 FileDescriptorProto extension_proto;
3018
3019 ASSERT_TRUE(TextFormat::ParseFromString(
3020 "name: 'extension.proto'"
3021 "extension { extendee: 'UnknownType' name:'some_extension' number:123"
3022 " label:LABEL_OPTIONAL type:TYPE_INT32 }",
3023 &extension_proto));
3024 const FileDescriptor* file = BuildFile(extension_proto);
3025
3026 ASSERT_TRUE(file != nullptr);
3027
3028 ASSERT_EQ(1, file->extension_count());
3029 const Descriptor* extendee = file->extension(0)->containing_type();
3030 EXPECT_EQ("UnknownType", extendee->name());
3031 EXPECT_TRUE(extendee->is_placeholder());
3032 ASSERT_EQ(1, extendee->extension_range_count());
3033 EXPECT_EQ(1, extendee->extension_range(0)->start);
3034 EXPECT_EQ(FieldDescriptor::kMaxNumber + 1, extendee->extension_range(0)->end);
3035 }
3036
TEST_P(AllowUnknownDependenciesTest,CustomOption)3037 TEST_P(AllowUnknownDependenciesTest, CustomOption) {
3038 // Test that we can use a custom option without having parsed
3039 // descriptor.proto.
3040
3041 FileDescriptorProto option_proto;
3042
3043 ASSERT_TRUE(TextFormat::ParseFromString(
3044 "name: \"unknown_custom_options.proto\" "
3045 "dependency: \"google/protobuf/descriptor.proto\" "
3046 "extension { "
3047 " extendee: \"google.protobuf.FileOptions\" "
3048 " name: \"some_option\" "
3049 " number: 123456 "
3050 " label: LABEL_OPTIONAL "
3051 " type: TYPE_INT32 "
3052 "} "
3053 "options { "
3054 " uninterpreted_option { "
3055 " name { "
3056 " name_part: \"some_option\" "
3057 " is_extension: true "
3058 " } "
3059 " positive_int_value: 1234 "
3060 " } "
3061 " uninterpreted_option { "
3062 " name { "
3063 " name_part: \"unknown_option\" "
3064 " is_extension: true "
3065 " } "
3066 " positive_int_value: 1234 "
3067 " } "
3068 " uninterpreted_option { "
3069 " name { "
3070 " name_part: \"optimize_for\" "
3071 " is_extension: false "
3072 " } "
3073 " identifier_value: \"SPEED\" "
3074 " } "
3075 "}",
3076 &option_proto));
3077
3078 const FileDescriptor* file = BuildFile(option_proto);
3079 ASSERT_TRUE(file != nullptr);
3080
3081 // Verify that no extension options were set, but they were left as
3082 // uninterpreted_options.
3083 std::vector<const FieldDescriptor*> fields;
3084 file->options().GetReflection()->ListFields(file->options(), &fields);
3085 ASSERT_EQ(2, fields.size());
3086 EXPECT_TRUE(file->options().has_optimize_for());
3087 EXPECT_EQ(2, file->options().uninterpreted_option_size());
3088 }
3089
TEST_P(AllowUnknownDependenciesTest,UndeclaredDependencyTriggersBuildOfDependency)3090 TEST_P(AllowUnknownDependenciesTest,
3091 UndeclaredDependencyTriggersBuildOfDependency) {
3092 // Crazy case: suppose foo.proto refers to a symbol without declaring the
3093 // dependency that finds it. In the event that the pool is backed by a
3094 // DescriptorDatabase, the pool will attempt to find the symbol in the
3095 // database. If successful, it will build the undeclared dependency to verify
3096 // that the file does indeed contain the symbol. If that file fails to build,
3097 // then its descriptors must be rolled back. However, we still want foo.proto
3098 // to build successfully, since we are allowing unknown dependencies.
3099
3100 FileDescriptorProto undeclared_dep_proto;
3101 // We make this file fail to build by giving it two fields with tag 1.
3102 ASSERT_TRUE(TextFormat::ParseFromString(
3103 "name: \"invalid_file_as_undeclared_dep.proto\" "
3104 "package: \"undeclared\" "
3105 "message_type: { "
3106 " name: \"Quux\" "
3107 " field { "
3108 " name:'qux' number:1 label:LABEL_OPTIONAL type: TYPE_INT32 "
3109 " }"
3110 " field { "
3111 " name:'quux' number:1 label:LABEL_OPTIONAL type: TYPE_INT64 "
3112 " }"
3113 "}",
3114 &undeclared_dep_proto));
3115 // We can't use the BuildFile() helper because we don't actually want to build
3116 // it into the descriptor pool in the fallback database case: it just needs to
3117 // be sitting in the database so that it gets built during the building of
3118 // test.proto below.
3119 switch (mode()) {
3120 case NO_DATABASE: {
3121 ASSERT_TRUE(pool_->BuildFile(undeclared_dep_proto) == nullptr);
3122 break;
3123 }
3124 case FALLBACK_DATABASE: {
3125 ASSERT_TRUE(db_.Add(undeclared_dep_proto));
3126 }
3127 }
3128
3129 FileDescriptorProto test_proto;
3130 ASSERT_TRUE(TextFormat::ParseFromString(
3131 "name: \"test.proto\" "
3132 "message_type: { "
3133 " name: \"Corge\" "
3134 " field { "
3135 " name:'quux' number:1 label: LABEL_OPTIONAL "
3136 " type_name:'undeclared.Quux' type: TYPE_MESSAGE "
3137 " }"
3138 "}",
3139 &test_proto));
3140
3141 const FileDescriptor* file = BuildFile(test_proto);
3142 ASSERT_TRUE(file != nullptr);
3143 GOOGLE_LOG(INFO) << file->DebugString();
3144
3145 EXPECT_EQ(0, file->dependency_count());
3146 ASSERT_EQ(1, file->message_type_count());
3147 const Descriptor* corge_desc = file->message_type(0);
3148 ASSERT_EQ("Corge", corge_desc->name());
3149 ASSERT_EQ(1, corge_desc->field_count());
3150 EXPECT_FALSE(corge_desc->is_placeholder());
3151
3152 const FieldDescriptor* quux_field = corge_desc->field(0);
3153 ASSERT_EQ(FieldDescriptor::TYPE_MESSAGE, quux_field->type());
3154 ASSERT_EQ("Quux", quux_field->message_type()->name());
3155 ASSERT_EQ("undeclared.Quux", quux_field->message_type()->full_name());
3156 EXPECT_TRUE(quux_field->message_type()->is_placeholder());
3157 // The place holder type should not be findable.
3158 ASSERT_TRUE(pool_->FindMessageTypeByName("undeclared.Quux") == nullptr);
3159 }
3160
3161 INSTANTIATE_TEST_SUITE_P(DatabaseSource, AllowUnknownDependenciesTest,
3162 testing::Combine(testing::Values(NO_DATABASE,
3163 FALLBACK_DATABASE),
3164 testing::Values("proto2", "proto3")));
3165
3166 // ===================================================================
3167
TEST(CustomOptions,OptionLocations)3168 TEST(CustomOptions, OptionLocations) {
3169 const Descriptor* message =
3170 protobuf_unittest::TestMessageWithCustomOptions::descriptor();
3171 const FileDescriptor* file = message->file();
3172 const FieldDescriptor* field = message->FindFieldByName("field1");
3173 const OneofDescriptor* oneof = message->FindOneofByName("AnOneof");
3174 const FieldDescriptor* map_field = message->FindFieldByName("map_field");
3175 const EnumDescriptor* enm = message->FindEnumTypeByName("AnEnum");
3176 // TODO(benjy): Support EnumValue options, once the compiler does.
3177 const ServiceDescriptor* service =
3178 file->FindServiceByName("TestServiceWithCustomOptions");
3179 const MethodDescriptor* method = service->FindMethodByName("Foo");
3180
3181 EXPECT_EQ(int64_t{9876543210},
3182 file->options().GetExtension(protobuf_unittest::file_opt1));
3183 EXPECT_EQ(-56,
3184 message->options().GetExtension(protobuf_unittest::message_opt1));
3185 EXPECT_EQ(int64_t{8765432109},
3186 field->options().GetExtension(protobuf_unittest::field_opt1));
3187 EXPECT_EQ(42, // Check that we get the default for an option we don't set.
3188 field->options().GetExtension(protobuf_unittest::field_opt2));
3189 EXPECT_EQ(-99, oneof->options().GetExtension(protobuf_unittest::oneof_opt1));
3190 EXPECT_EQ(int64_t{12345},
3191 map_field->options().GetExtension(protobuf_unittest::field_opt1));
3192 EXPECT_EQ(-789, enm->options().GetExtension(protobuf_unittest::enum_opt1));
3193 EXPECT_EQ(123, enm->value(1)->options().GetExtension(
3194 protobuf_unittest::enum_value_opt1));
3195 EXPECT_EQ(int64_t{-9876543210},
3196 service->options().GetExtension(protobuf_unittest::service_opt1));
3197 EXPECT_EQ(protobuf_unittest::METHODOPT1_VAL2,
3198 method->options().GetExtension(protobuf_unittest::method_opt1));
3199
3200 // See that the regular options went through unscathed.
3201 EXPECT_TRUE(message->options().has_message_set_wire_format());
3202 EXPECT_EQ(FieldOptions::CORD, field->options().ctype());
3203 }
3204
TEST(CustomOptions,OptionTypes)3205 TEST(CustomOptions, OptionTypes) {
3206 const MessageOptions* options = nullptr;
3207
3208 constexpr int32_t kint32min = std::numeric_limits<int32_t>::min();
3209 constexpr int32_t kint32max = std::numeric_limits<int32_t>::max();
3210 constexpr uint32_t kuint32max = std::numeric_limits<uint32_t>::max();
3211 constexpr int64_t kint64min = std::numeric_limits<int64_t>::min();
3212 constexpr int64_t kint64max = std::numeric_limits<int64_t>::max();
3213 constexpr uint64_t kuint64max = std::numeric_limits<uint64_t>::max();
3214
3215 options =
3216 &protobuf_unittest::CustomOptionMinIntegerValues::descriptor()->options();
3217 EXPECT_EQ(false, options->GetExtension(protobuf_unittest::bool_opt));
3218 EXPECT_EQ(kint32min, options->GetExtension(protobuf_unittest::int32_opt));
3219 EXPECT_EQ(kint64min, options->GetExtension(protobuf_unittest::int64_opt));
3220 EXPECT_EQ(0, options->GetExtension(protobuf_unittest::uint32_opt));
3221 EXPECT_EQ(0, options->GetExtension(protobuf_unittest::uint64_opt));
3222 EXPECT_EQ(kint32min, options->GetExtension(protobuf_unittest::sint32_opt));
3223 EXPECT_EQ(kint64min, options->GetExtension(protobuf_unittest::sint64_opt));
3224 EXPECT_EQ(0, options->GetExtension(protobuf_unittest::fixed32_opt));
3225 EXPECT_EQ(0, options->GetExtension(protobuf_unittest::fixed64_opt));
3226 EXPECT_EQ(kint32min, options->GetExtension(protobuf_unittest::sfixed32_opt));
3227 EXPECT_EQ(kint64min, options->GetExtension(protobuf_unittest::sfixed64_opt));
3228
3229 options =
3230 &protobuf_unittest::CustomOptionMaxIntegerValues::descriptor()->options();
3231 EXPECT_EQ(true, options->GetExtension(protobuf_unittest::bool_opt));
3232 EXPECT_EQ(kint32max, options->GetExtension(protobuf_unittest::int32_opt));
3233 EXPECT_EQ(kint64max, options->GetExtension(protobuf_unittest::int64_opt));
3234 EXPECT_EQ(kuint32max, options->GetExtension(protobuf_unittest::uint32_opt));
3235 EXPECT_EQ(kuint64max, options->GetExtension(protobuf_unittest::uint64_opt));
3236 EXPECT_EQ(kint32max, options->GetExtension(protobuf_unittest::sint32_opt));
3237 EXPECT_EQ(kint64max, options->GetExtension(protobuf_unittest::sint64_opt));
3238 EXPECT_EQ(kuint32max, options->GetExtension(protobuf_unittest::fixed32_opt));
3239 EXPECT_EQ(kuint64max, options->GetExtension(protobuf_unittest::fixed64_opt));
3240 EXPECT_EQ(kint32max, options->GetExtension(protobuf_unittest::sfixed32_opt));
3241 EXPECT_EQ(kint64max, options->GetExtension(protobuf_unittest::sfixed64_opt));
3242
3243 options = &protobuf_unittest::CustomOptionOtherValues::descriptor()->options();
3244 EXPECT_EQ(-100, options->GetExtension(protobuf_unittest::int32_opt));
3245 EXPECT_FLOAT_EQ(12.3456789,
3246 options->GetExtension(protobuf_unittest::float_opt));
3247 EXPECT_DOUBLE_EQ(1.234567890123456789,
3248 options->GetExtension(protobuf_unittest::double_opt));
3249 EXPECT_EQ("Hello, \"World\"",
3250 options->GetExtension(protobuf_unittest::string_opt));
3251
3252 EXPECT_EQ(std::string("Hello\0World", 11),
3253 options->GetExtension(protobuf_unittest::bytes_opt));
3254
3255 EXPECT_EQ(protobuf_unittest::DummyMessageContainingEnum::TEST_OPTION_ENUM_TYPE2,
3256 options->GetExtension(protobuf_unittest::enum_opt));
3257
3258 options =
3259 &protobuf_unittest::SettingRealsFromPositiveInts::descriptor()->options();
3260 EXPECT_FLOAT_EQ(12, options->GetExtension(protobuf_unittest::float_opt));
3261 EXPECT_DOUBLE_EQ(154, options->GetExtension(protobuf_unittest::double_opt));
3262
3263 options =
3264 &protobuf_unittest::SettingRealsFromNegativeInts::descriptor()->options();
3265 EXPECT_FLOAT_EQ(-12, options->GetExtension(protobuf_unittest::float_opt));
3266 EXPECT_DOUBLE_EQ(-154, options->GetExtension(protobuf_unittest::double_opt));
3267 }
3268
TEST(CustomOptions,ComplexExtensionOptions)3269 TEST(CustomOptions, ComplexExtensionOptions) {
3270 const MessageOptions* options =
3271 &protobuf_unittest::VariousComplexOptions::descriptor()->options();
3272 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt1).foo(), 42);
3273 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt1)
3274 .GetExtension(protobuf_unittest::quux),
3275 324);
3276 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt1)
3277 .GetExtension(protobuf_unittest::corge)
3278 .qux(),
3279 876);
3280 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2).baz(), 987);
3281 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2)
3282 .GetExtension(protobuf_unittest::grault),
3283 654);
3284 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2).bar().foo(),
3285 743);
3286 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2)
3287 .bar()
3288 .GetExtension(protobuf_unittest::quux),
3289 1999);
3290 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2)
3291 .bar()
3292 .GetExtension(protobuf_unittest::corge)
3293 .qux(),
3294 2008);
3295 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2)
3296 .GetExtension(protobuf_unittest::garply)
3297 .foo(),
3298 741);
3299 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2)
3300 .GetExtension(protobuf_unittest::garply)
3301 .GetExtension(protobuf_unittest::quux),
3302 1998);
3303 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2)
3304 .GetExtension(protobuf_unittest::garply)
3305 .GetExtension(protobuf_unittest::corge)
3306 .qux(),
3307 2121);
3308 EXPECT_EQ(options
3309 ->GetExtension(protobuf_unittest::ComplexOptionType2::
3310 ComplexOptionType4::complex_opt4)
3311 .waldo(),
3312 1971);
3313 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2).fred().waldo(),
3314 321);
3315 EXPECT_EQ(9, options->GetExtension(protobuf_unittest::complex_opt3).qux());
3316 EXPECT_EQ(22, options->GetExtension(protobuf_unittest::complex_opt3)
3317 .complexoptiontype5()
3318 .plugh());
3319 EXPECT_EQ(24, options->GetExtension(protobuf_unittest::complexopt6).xyzzy());
3320 }
3321
TEST(CustomOptions,OptionsFromOtherFile)3322 TEST(CustomOptions, OptionsFromOtherFile) {
3323 // Test that to use a custom option, we only need to import the file
3324 // defining the option; we do not also have to import descriptor.proto.
3325 DescriptorPool pool;
3326
3327 FileDescriptorProto file_proto;
3328 FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto);
3329 ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
3330
3331 // We have to import the Any dependency.
3332 FileDescriptorProto any_proto;
3333 google::protobuf::Any::descriptor()->file()->CopyTo(&any_proto);
3334 ASSERT_TRUE(pool.BuildFile(any_proto) != nullptr);
3335
3336 protobuf_unittest::TestMessageWithCustomOptions::descriptor()->file()->CopyTo(
3337 &file_proto);
3338 ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
3339
3340 ASSERT_TRUE(TextFormat::ParseFromString(
3341 "name: \"custom_options_import.proto\" "
3342 "package: \"protobuf_unittest\" "
3343 "dependency: \"google/protobuf/unittest_custom_options.proto\" "
3344 "options { "
3345 " uninterpreted_option { "
3346 " name { "
3347 " name_part: \"file_opt1\" "
3348 " is_extension: true "
3349 " } "
3350 " positive_int_value: 1234 "
3351 " } "
3352 // Test a non-extension option too. (At one point this failed due to a
3353 // bug.)
3354 " uninterpreted_option { "
3355 " name { "
3356 " name_part: \"java_package\" "
3357 " is_extension: false "
3358 " } "
3359 " string_value: \"foo\" "
3360 " } "
3361 // Test that enum-typed options still work too. (At one point this also
3362 // failed due to a bug.)
3363 " uninterpreted_option { "
3364 " name { "
3365 " name_part: \"optimize_for\" "
3366 " is_extension: false "
3367 " } "
3368 " identifier_value: \"SPEED\" "
3369 " } "
3370 "}",
3371 &file_proto));
3372
3373 const FileDescriptor* file = pool.BuildFile(file_proto);
3374 ASSERT_TRUE(file != nullptr);
3375 EXPECT_EQ(1234, file->options().GetExtension(protobuf_unittest::file_opt1));
3376 EXPECT_TRUE(file->options().has_java_package());
3377 EXPECT_EQ("foo", file->options().java_package());
3378 EXPECT_TRUE(file->options().has_optimize_for());
3379 EXPECT_EQ(FileOptions::SPEED, file->options().optimize_for());
3380 }
3381
TEST(CustomOptions,MessageOptionThreeFieldsSet)3382 TEST(CustomOptions, MessageOptionThreeFieldsSet) {
3383 // This tests a bug which previously existed in custom options parsing. The
3384 // bug occurred when you defined a custom option with message type and then
3385 // set three fields of that option on a single definition (see the example
3386 // below). The bug is a bit hard to explain, so check the change history if
3387 // you want to know more.
3388 DescriptorPool pool;
3389
3390 FileDescriptorProto file_proto;
3391 FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto);
3392 ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
3393
3394 FileDescriptorProto any_proto;
3395 google::protobuf::Any::descriptor()->file()->CopyTo(&any_proto);
3396 ASSERT_TRUE(pool.BuildFile(any_proto) != nullptr);
3397
3398 protobuf_unittest::TestMessageWithCustomOptions::descriptor()->file()->CopyTo(
3399 &file_proto);
3400 ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
3401
3402 // The following represents the definition:
3403 //
3404 // import "google/protobuf/unittest_custom_options.proto"
3405 // package protobuf_unittest;
3406 // message Foo {
3407 // option (complex_opt1).foo = 1234;
3408 // option (complex_opt1).foo2 = 1234;
3409 // option (complex_opt1).foo3 = 1234;
3410 // }
3411 ASSERT_TRUE(TextFormat::ParseFromString(
3412 "name: \"custom_options_import.proto\" "
3413 "package: \"protobuf_unittest\" "
3414 "dependency: \"google/protobuf/unittest_custom_options.proto\" "
3415 "message_type { "
3416 " name: \"Foo\" "
3417 " options { "
3418 " uninterpreted_option { "
3419 " name { "
3420 " name_part: \"complex_opt1\" "
3421 " is_extension: true "
3422 " } "
3423 " name { "
3424 " name_part: \"foo\" "
3425 " is_extension: false "
3426 " } "
3427 " positive_int_value: 1234 "
3428 " } "
3429 " uninterpreted_option { "
3430 " name { "
3431 " name_part: \"complex_opt1\" "
3432 " is_extension: true "
3433 " } "
3434 " name { "
3435 " name_part: \"foo2\" "
3436 " is_extension: false "
3437 " } "
3438 " positive_int_value: 1234 "
3439 " } "
3440 " uninterpreted_option { "
3441 " name { "
3442 " name_part: \"complex_opt1\" "
3443 " is_extension: true "
3444 " } "
3445 " name { "
3446 " name_part: \"foo3\" "
3447 " is_extension: false "
3448 " } "
3449 " positive_int_value: 1234 "
3450 " } "
3451 " } "
3452 "}",
3453 &file_proto));
3454
3455 const FileDescriptor* file = pool.BuildFile(file_proto);
3456 ASSERT_TRUE(file != nullptr);
3457 ASSERT_EQ(1, file->message_type_count());
3458
3459 const MessageOptions& options = file->message_type(0)->options();
3460 EXPECT_EQ(1234, options.GetExtension(protobuf_unittest::complex_opt1).foo());
3461 }
3462
TEST(CustomOptions,MessageOptionRepeatedLeafFieldSet)3463 TEST(CustomOptions, MessageOptionRepeatedLeafFieldSet) {
3464 // This test verifies that repeated fields in custom options can be
3465 // given multiple values by repeating the option with a different value.
3466 // This test checks repeated leaf values. Each repeated custom value
3467 // appears in a different uninterpreted_option, which will be concatenated
3468 // when they are merged into the final option value.
3469 DescriptorPool pool;
3470
3471 FileDescriptorProto file_proto;
3472 FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto);
3473 ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
3474
3475 FileDescriptorProto any_proto;
3476 google::protobuf::Any::descriptor()->file()->CopyTo(&any_proto);
3477 ASSERT_TRUE(pool.BuildFile(any_proto) != nullptr);
3478
3479 protobuf_unittest::TestMessageWithCustomOptions::descriptor()->file()->CopyTo(
3480 &file_proto);
3481 ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
3482
3483 // The following represents the definition:
3484 //
3485 // import "google/protobuf/unittest_custom_options.proto"
3486 // package protobuf_unittest;
3487 // message Foo {
3488 // option (complex_opt1).foo4 = 12;
3489 // option (complex_opt1).foo4 = 34;
3490 // option (complex_opt1).foo4 = 56;
3491 // }
3492 ASSERT_TRUE(TextFormat::ParseFromString(
3493 "name: \"custom_options_import.proto\" "
3494 "package: \"protobuf_unittest\" "
3495 "dependency: \"google/protobuf/unittest_custom_options.proto\" "
3496 "message_type { "
3497 " name: \"Foo\" "
3498 " options { "
3499 " uninterpreted_option { "
3500 " name { "
3501 " name_part: \"complex_opt1\" "
3502 " is_extension: true "
3503 " } "
3504 " name { "
3505 " name_part: \"foo4\" "
3506 " is_extension: false "
3507 " } "
3508 " positive_int_value: 12 "
3509 " } "
3510 " uninterpreted_option { "
3511 " name { "
3512 " name_part: \"complex_opt1\" "
3513 " is_extension: true "
3514 " } "
3515 " name { "
3516 " name_part: \"foo4\" "
3517 " is_extension: false "
3518 " } "
3519 " positive_int_value: 34 "
3520 " } "
3521 " uninterpreted_option { "
3522 " name { "
3523 " name_part: \"complex_opt1\" "
3524 " is_extension: true "
3525 " } "
3526 " name { "
3527 " name_part: \"foo4\" "
3528 " is_extension: false "
3529 " } "
3530 " positive_int_value: 56 "
3531 " } "
3532 " } "
3533 "}",
3534 &file_proto));
3535
3536 const FileDescriptor* file = pool.BuildFile(file_proto);
3537 ASSERT_TRUE(file != nullptr);
3538 ASSERT_EQ(1, file->message_type_count());
3539
3540 const MessageOptions& options = file->message_type(0)->options();
3541 EXPECT_EQ(3, options.GetExtension(protobuf_unittest::complex_opt1).foo4_size());
3542 EXPECT_EQ(12, options.GetExtension(protobuf_unittest::complex_opt1).foo4(0));
3543 EXPECT_EQ(34, options.GetExtension(protobuf_unittest::complex_opt1).foo4(1));
3544 EXPECT_EQ(56, options.GetExtension(protobuf_unittest::complex_opt1).foo4(2));
3545 }
3546
TEST(CustomOptions,MessageOptionRepeatedMsgFieldSet)3547 TEST(CustomOptions, MessageOptionRepeatedMsgFieldSet) {
3548 // This test verifies that repeated fields in custom options can be
3549 // given multiple values by repeating the option with a different value.
3550 // This test checks repeated message values. Each repeated custom value
3551 // appears in a different uninterpreted_option, which will be concatenated
3552 // when they are merged into the final option value.
3553 DescriptorPool pool;
3554
3555 FileDescriptorProto file_proto;
3556 FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto);
3557 ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
3558
3559 FileDescriptorProto any_proto;
3560 google::protobuf::Any::descriptor()->file()->CopyTo(&any_proto);
3561 ASSERT_TRUE(pool.BuildFile(any_proto) != nullptr);
3562
3563 protobuf_unittest::TestMessageWithCustomOptions::descriptor()->file()->CopyTo(
3564 &file_proto);
3565 ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
3566
3567 // The following represents the definition:
3568 //
3569 // import "google/protobuf/unittest_custom_options.proto"
3570 // package protobuf_unittest;
3571 // message Foo {
3572 // option (complex_opt2).barney = {waldo: 1};
3573 // option (complex_opt2).barney = {waldo: 10};
3574 // option (complex_opt2).barney = {waldo: 100};
3575 // }
3576 ASSERT_TRUE(TextFormat::ParseFromString(
3577 "name: \"custom_options_import.proto\" "
3578 "package: \"protobuf_unittest\" "
3579 "dependency: \"google/protobuf/unittest_custom_options.proto\" "
3580 "message_type { "
3581 " name: \"Foo\" "
3582 " options { "
3583 " uninterpreted_option { "
3584 " name { "
3585 " name_part: \"complex_opt2\" "
3586 " is_extension: true "
3587 " } "
3588 " name { "
3589 " name_part: \"barney\" "
3590 " is_extension: false "
3591 " } "
3592 " aggregate_value: \"waldo: 1\" "
3593 " } "
3594 " uninterpreted_option { "
3595 " name { "
3596 " name_part: \"complex_opt2\" "
3597 " is_extension: true "
3598 " } "
3599 " name { "
3600 " name_part: \"barney\" "
3601 " is_extension: false "
3602 " } "
3603 " aggregate_value: \"waldo: 10\" "
3604 " } "
3605 " uninterpreted_option { "
3606 " name { "
3607 " name_part: \"complex_opt2\" "
3608 " is_extension: true "
3609 " } "
3610 " name { "
3611 " name_part: \"barney\" "
3612 " is_extension: false "
3613 " } "
3614 " aggregate_value: \"waldo: 100\" "
3615 " } "
3616 " } "
3617 "}",
3618 &file_proto));
3619
3620 const FileDescriptor* file = pool.BuildFile(file_proto);
3621 ASSERT_TRUE(file != nullptr);
3622 ASSERT_EQ(1, file->message_type_count());
3623
3624 const MessageOptions& options = file->message_type(0)->options();
3625 EXPECT_EQ(3,
3626 options.GetExtension(protobuf_unittest::complex_opt2).barney_size());
3627 EXPECT_EQ(
3628 1, options.GetExtension(protobuf_unittest::complex_opt2).barney(0).waldo());
3629 EXPECT_EQ(
3630 10,
3631 options.GetExtension(protobuf_unittest::complex_opt2).barney(1).waldo());
3632 EXPECT_EQ(
3633 100,
3634 options.GetExtension(protobuf_unittest::complex_opt2).barney(2).waldo());
3635 }
3636
3637 // Check that aggregate options were parsed and saved correctly in
3638 // the appropriate descriptors.
TEST(CustomOptions,AggregateOptions)3639 TEST(CustomOptions, AggregateOptions) {
3640 const Descriptor* msg = protobuf_unittest::AggregateMessage::descriptor();
3641 const FileDescriptor* file = msg->file();
3642 const FieldDescriptor* field = msg->FindFieldByName("fieldname");
3643 const EnumDescriptor* enumd = file->FindEnumTypeByName("AggregateEnum");
3644 const EnumValueDescriptor* enumv = enumd->FindValueByName("VALUE");
3645 const ServiceDescriptor* service =
3646 file->FindServiceByName("AggregateService");
3647 const MethodDescriptor* method = service->FindMethodByName("Method");
3648
3649 // Tests for the different types of data embedded in fileopt
3650 const protobuf_unittest::Aggregate& file_options =
3651 file->options().GetExtension(protobuf_unittest::fileopt);
3652 EXPECT_EQ(100, file_options.i());
3653 EXPECT_EQ("FileAnnotation", file_options.s());
3654 EXPECT_EQ("NestedFileAnnotation", file_options.sub().s());
3655 EXPECT_EQ("FileExtensionAnnotation",
3656 file_options.file().GetExtension(protobuf_unittest::fileopt).s());
3657 EXPECT_EQ("EmbeddedMessageSetElement",
3658 file_options.mset()
3659 .GetExtension(protobuf_unittest::AggregateMessageSetElement ::
3660 message_set_extension)
3661 .s());
3662
3663 protobuf_unittest::AggregateMessageSetElement any_payload;
3664 ASSERT_TRUE(file_options.any().UnpackTo(&any_payload));
3665 EXPECT_EQ("EmbeddedMessageSetElement", any_payload.s());
3666
3667 // Simple tests for all the other types of annotations
3668 EXPECT_EQ("MessageAnnotation",
3669 msg->options().GetExtension(protobuf_unittest::msgopt).s());
3670 EXPECT_EQ("FieldAnnotation",
3671 field->options().GetExtension(protobuf_unittest::fieldopt).s());
3672 EXPECT_EQ("EnumAnnotation",
3673 enumd->options().GetExtension(protobuf_unittest::enumopt).s());
3674 EXPECT_EQ("EnumValueAnnotation",
3675 enumv->options().GetExtension(protobuf_unittest::enumvalopt).s());
3676 EXPECT_EQ("ServiceAnnotation",
3677 service->options().GetExtension(protobuf_unittest::serviceopt).s());
3678 EXPECT_EQ("MethodAnnotation",
3679 method->options().GetExtension(protobuf_unittest::methodopt).s());
3680 }
3681
TEST(CustomOptions,UnusedImportError)3682 TEST(CustomOptions, UnusedImportError) {
3683 DescriptorPool pool;
3684
3685 FileDescriptorProto file_proto;
3686 FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto);
3687 ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
3688
3689 FileDescriptorProto any_proto;
3690 google::protobuf::Any::descriptor()->file()->CopyTo(&any_proto);
3691 ASSERT_TRUE(pool.BuildFile(any_proto) != nullptr);
3692
3693 protobuf_unittest::TestMessageWithCustomOptions::descriptor()->file()->CopyTo(
3694 &file_proto);
3695 ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
3696
3697 pool.AddUnusedImportTrackFile("custom_options_import.proto", true);
3698 ASSERT_TRUE(TextFormat::ParseFromString(
3699 "name: \"custom_options_import.proto\" "
3700 "package: \"protobuf_unittest\" "
3701 "dependency: \"google/protobuf/unittest_custom_options.proto\" ",
3702 &file_proto));
3703
3704 MockErrorCollector error_collector;
3705 EXPECT_FALSE(pool.BuildFileCollectingErrors(file_proto, &error_collector));
3706 EXPECT_EQ(
3707 "custom_options_import.proto: "
3708 "google/protobuf/unittest_custom_options.proto: IMPORT: Import "
3709 "google/protobuf/unittest_custom_options.proto is unused.\n",
3710 error_collector.text_);
3711 }
3712
3713 // Verifies that proto files can correctly be parsed, even if the
3714 // custom options defined in the file are incompatible with those
3715 // compiled in the binary. See http://b/19276250.
TEST(CustomOptions,OptionsWithIncompatibleDescriptors)3716 TEST(CustomOptions, OptionsWithIncompatibleDescriptors) {
3717 DescriptorPool pool;
3718
3719 FileDescriptorProto file_proto;
3720 MessageOptions::descriptor()->file()->CopyTo(&file_proto);
3721 ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
3722
3723 // Create a new file descriptor proto containing a subset of the
3724 // messages defined in google/protobuf/unittest_custom_options.proto.
3725 file_proto.Clear();
3726 file_proto.set_name("unittest_custom_options.proto");
3727 file_proto.set_package("protobuf_unittest");
3728 file_proto.add_dependency("google/protobuf/descriptor.proto");
3729
3730 // Add the "required_enum_opt" extension.
3731 FieldDescriptorProto* extension = file_proto.add_extension();
3732 protobuf_unittest::OldOptionType::descriptor()
3733 ->file()
3734 ->FindExtensionByName("required_enum_opt")
3735 ->CopyTo(extension);
3736
3737 // Add a test message that uses the "required_enum_opt" option.
3738 DescriptorProto* test_message_type = file_proto.add_message_type();
3739 protobuf_unittest::TestMessageWithRequiredEnumOption::descriptor()->CopyTo(
3740 test_message_type);
3741
3742 // Instruct the extension to use NewOptionType instead of
3743 // OldOptionType, and add the descriptor of NewOptionType.
3744 extension->set_type_name(".protobuf_unittest.NewOptionType");
3745 DescriptorProto* new_option_type = file_proto.add_message_type();
3746 protobuf_unittest::NewOptionType::descriptor()->CopyTo(new_option_type);
3747
3748 // Replace the value of the "required_enum_opt" option used in the
3749 // test message with an enum value that only exists in NewOptionType.
3750 ASSERT_TRUE(
3751 TextFormat::ParseFromString("uninterpreted_option { "
3752 " name { "
3753 " name_part: 'required_enum_opt' "
3754 " is_extension: true "
3755 " } "
3756 " aggregate_value: 'value: NEW_VALUE'"
3757 "}",
3758 test_message_type->mutable_options()));
3759
3760 // Adding the file descriptor to the pool should fail.
3761 EXPECT_TRUE(pool.BuildFile(file_proto) == nullptr);
3762 }
3763
3764 // Test that FileDescriptor::DebugString() formats custom options correctly.
TEST(CustomOptions,DebugString)3765 TEST(CustomOptions, DebugString) {
3766 DescriptorPool pool;
3767
3768 FileDescriptorProto file_proto;
3769 MessageOptions::descriptor()->file()->CopyTo(&file_proto);
3770 ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
3771
3772 // Add "foo.proto":
3773 // import "google/protobuf/descriptor.proto";
3774 // package "protobuf_unittest";
3775 // option (protobuf_unittest.cc_option1) = 1;
3776 // option (protobuf_unittest.cc_option2) = 2;
3777 // extend google.protobuf.FieldOptions {
3778 // optional int32 cc_option1 = 7736974;
3779 // optional int32 cc_option2 = 7736975;
3780 // }
3781 ASSERT_TRUE(TextFormat::ParseFromString(
3782 "name: \"foo.proto\" "
3783 "package: \"protobuf_unittest\" "
3784 "dependency: \"google/protobuf/descriptor.proto\" "
3785 "options { "
3786 " uninterpreted_option { "
3787 " name { "
3788 " name_part: \"protobuf_unittest.cc_option1\" "
3789 " is_extension: true "
3790 " } "
3791 " positive_int_value: 1 "
3792 " } "
3793 " uninterpreted_option { "
3794 " name { "
3795 " name_part: \"protobuf_unittest.cc_option2\" "
3796 " is_extension: true "
3797 " } "
3798 " positive_int_value: 2 "
3799 " } "
3800 "} "
3801 "extension { "
3802 " name: \"cc_option1\" "
3803 " extendee: \".google.protobuf.FileOptions\" "
3804 // This field number is intentionally chosen to be the same as
3805 // (.fileopt1) defined in unittest_custom_options.proto (linked
3806 // in this test binary). This is to test whether we are messing
3807 // generated pool with custom descriptor pools when dealing with
3808 // custom options.
3809 " number: 7736974 "
3810 " label: LABEL_OPTIONAL "
3811 " type: TYPE_INT32 "
3812 "}"
3813 "extension { "
3814 " name: \"cc_option2\" "
3815 " extendee: \".google.protobuf.FileOptions\" "
3816 " number: 7736975 "
3817 " label: LABEL_OPTIONAL "
3818 " type: TYPE_INT32 "
3819 "}",
3820 &file_proto));
3821 const FileDescriptor* descriptor = pool.BuildFile(file_proto);
3822 ASSERT_TRUE(descriptor != nullptr);
3823
3824 EXPECT_EQ(2, descriptor->extension_count());
3825
3826 ASSERT_EQ(
3827 "syntax = \"proto2\";\n"
3828 "\n"
3829 "import \"google/protobuf/descriptor.proto\";\n"
3830 "package protobuf_unittest;\n"
3831 "\n"
3832 "option (.protobuf_unittest.cc_option1) = 1;\n"
3833 "option (.protobuf_unittest.cc_option2) = 2;\n"
3834 "\n"
3835 "extend .google.protobuf.FileOptions {\n"
3836 " optional int32 cc_option1 = 7736974;\n"
3837 " optional int32 cc_option2 = 7736975;\n"
3838 "}\n"
3839 "\n",
3840 descriptor->DebugString());
3841 }
3842
3843 // ===================================================================
3844
3845 class ValidationErrorTest : public testing::Test {
3846 protected:
3847 // Parse file_text as a FileDescriptorProto in text format and add it
3848 // to the DescriptorPool. Expect no errors.
BuildFile(const std::string & file_text)3849 const FileDescriptor* BuildFile(const std::string& file_text) {
3850 FileDescriptorProto file_proto;
3851 EXPECT_TRUE(TextFormat::ParseFromString(file_text, &file_proto));
3852 return GOOGLE_CHECK_NOTNULL(pool_.BuildFile(file_proto));
3853 }
3854
3855 // Parse file_text as a FileDescriptorProto in text format and add it
3856 // to the DescriptorPool. Expect errors to be produced which match the
3857 // given error text.
BuildFileWithErrors(const std::string & file_text,const std::string & expected_errors)3858 void BuildFileWithErrors(const std::string& file_text,
3859 const std::string& expected_errors) {
3860 FileDescriptorProto file_proto;
3861 ASSERT_TRUE(TextFormat::ParseFromString(file_text, &file_proto));
3862
3863 MockErrorCollector error_collector;
3864 EXPECT_TRUE(pool_.BuildFileCollectingErrors(file_proto, &error_collector) ==
3865 nullptr);
3866 EXPECT_EQ(expected_errors, error_collector.text_);
3867 }
3868
3869 // Parse file_text as a FileDescriptorProto in text format and add it
3870 // to the DescriptorPool. Expect errors to be produced which match the
3871 // given warning text.
BuildFileWithWarnings(const std::string & file_text,const std::string & expected_warnings)3872 void BuildFileWithWarnings(const std::string& file_text,
3873 const std::string& expected_warnings) {
3874 FileDescriptorProto file_proto;
3875 ASSERT_TRUE(TextFormat::ParseFromString(file_text, &file_proto));
3876
3877 MockErrorCollector error_collector;
3878 EXPECT_TRUE(pool_.BuildFileCollectingErrors(file_proto, &error_collector));
3879 EXPECT_EQ(expected_warnings, error_collector.warning_text_);
3880 }
3881
3882 // Builds some already-parsed file in our test pool.
BuildFileInTestPool(const FileDescriptor * file)3883 void BuildFileInTestPool(const FileDescriptor* file) {
3884 FileDescriptorProto file_proto;
3885 file->CopyTo(&file_proto);
3886 ASSERT_TRUE(pool_.BuildFile(file_proto) != nullptr);
3887 }
3888
3889 // Build descriptor.proto in our test pool. This allows us to extend it in
3890 // the test pool, so we can test custom options.
BuildDescriptorMessagesInTestPool()3891 void BuildDescriptorMessagesInTestPool() {
3892 BuildFileInTestPool(DescriptorProto::descriptor()->file());
3893 }
3894
3895 DescriptorPool pool_;
3896 };
3897
TEST_F(ValidationErrorTest,AlreadyDefined)3898 TEST_F(ValidationErrorTest, AlreadyDefined) {
3899 BuildFileWithErrors(
3900 "name: \"foo.proto\" "
3901 "message_type { name: \"Foo\" }"
3902 "message_type { name: \"Foo\" }",
3903
3904 "foo.proto: Foo: NAME: \"Foo\" is already defined.\n");
3905 }
3906
TEST_F(ValidationErrorTest,AlreadyDefinedInPackage)3907 TEST_F(ValidationErrorTest, AlreadyDefinedInPackage) {
3908 BuildFileWithErrors(
3909 "name: \"foo.proto\" "
3910 "package: \"foo.bar\" "
3911 "message_type { name: \"Foo\" }"
3912 "message_type { name: \"Foo\" }",
3913
3914 "foo.proto: foo.bar.Foo: NAME: \"Foo\" is already defined in "
3915 "\"foo.bar\".\n");
3916 }
3917
TEST_F(ValidationErrorTest,AlreadyDefinedInOtherFile)3918 TEST_F(ValidationErrorTest, AlreadyDefinedInOtherFile) {
3919 BuildFile(
3920 "name: \"foo.proto\" "
3921 "message_type { name: \"Foo\" }");
3922
3923 BuildFileWithErrors(
3924 "name: \"bar.proto\" "
3925 "message_type { name: \"Foo\" }",
3926
3927 "bar.proto: Foo: NAME: \"Foo\" is already defined in file "
3928 "\"foo.proto\".\n");
3929 }
3930
TEST_F(ValidationErrorTest,PackageAlreadyDefined)3931 TEST_F(ValidationErrorTest, PackageAlreadyDefined) {
3932 BuildFile(
3933 "name: \"foo.proto\" "
3934 "message_type { name: \"foo\" }");
3935 BuildFileWithErrors(
3936 "name: \"bar.proto\" "
3937 "package: \"foo.bar\"",
3938
3939 "bar.proto: foo: NAME: \"foo\" is already defined (as something other "
3940 "than a package) in file \"foo.proto\".\n");
3941 }
3942
TEST_F(ValidationErrorTest,EnumValueAlreadyDefinedInParent)3943 TEST_F(ValidationErrorTest, EnumValueAlreadyDefinedInParent) {
3944 BuildFileWithErrors(
3945 "name: \"foo.proto\" "
3946 "enum_type { name: \"Foo\" value { name: \"FOO\" number: 1 } } "
3947 "enum_type { name: \"Bar\" value { name: \"FOO\" number: 1 } } ",
3948
3949 "foo.proto: FOO: NAME: \"FOO\" is already defined.\n"
3950 "foo.proto: FOO: NAME: Note that enum values use C++ scoping rules, "
3951 "meaning that enum values are siblings of their type, not children of "
3952 "it. Therefore, \"FOO\" must be unique within the global scope, not "
3953 "just within \"Bar\".\n");
3954 }
3955
TEST_F(ValidationErrorTest,EnumValueAlreadyDefinedInParentNonGlobal)3956 TEST_F(ValidationErrorTest, EnumValueAlreadyDefinedInParentNonGlobal) {
3957 BuildFileWithErrors(
3958 "name: \"foo.proto\" "
3959 "package: \"pkg\" "
3960 "enum_type { name: \"Foo\" value { name: \"FOO\" number: 1 } } "
3961 "enum_type { name: \"Bar\" value { name: \"FOO\" number: 1 } } ",
3962
3963 "foo.proto: pkg.FOO: NAME: \"FOO\" is already defined in \"pkg\".\n"
3964 "foo.proto: pkg.FOO: NAME: Note that enum values use C++ scoping rules, "
3965 "meaning that enum values are siblings of their type, not children of "
3966 "it. Therefore, \"FOO\" must be unique within \"pkg\", not just within "
3967 "\"Bar\".\n");
3968 }
3969
TEST_F(ValidationErrorTest,MissingName)3970 TEST_F(ValidationErrorTest, MissingName) {
3971 BuildFileWithErrors(
3972 "name: \"foo.proto\" "
3973 "message_type { }",
3974
3975 "foo.proto: : NAME: Missing name.\n");
3976 }
3977
TEST_F(ValidationErrorTest,InvalidName)3978 TEST_F(ValidationErrorTest, InvalidName) {
3979 BuildFileWithErrors(
3980 "name: \"foo.proto\" "
3981 "message_type { name: \"$\" }",
3982
3983 "foo.proto: $: NAME: \"$\" is not a valid identifier.\n");
3984 }
3985
TEST_F(ValidationErrorTest,InvalidPackageName)3986 TEST_F(ValidationErrorTest, InvalidPackageName) {
3987 BuildFileWithErrors(
3988 "name: \"foo.proto\" "
3989 "package: \"foo.$\"",
3990
3991 "foo.proto: foo.$: NAME: \"$\" is not a valid identifier.\n");
3992 }
3993
3994 // 'str' is a static C-style string that may contain '\0'
3995 #define STATIC_STR(str) std::string((str), sizeof(str) - 1)
3996
TEST_F(ValidationErrorTest,NullCharSymbolName)3997 TEST_F(ValidationErrorTest, NullCharSymbolName) {
3998 BuildFileWithErrors(
3999 "name: \"bar.proto\" "
4000 "package: \"foo\""
4001 "message_type { "
4002 " name: '\\000\\001\\013.Bar' "
4003 " field { name: \"foo\" number: 9 label:LABEL_OPTIONAL type:TYPE_INT32 "
4004 "} "
4005 "}",
4006 STATIC_STR("bar.proto: foo.\0\x1\v.Bar: NAME: \"\0\x1\v.Bar\" is not a "
4007 "valid identifier.\nbar.proto: foo.\0\x1\v.Bar.foo: NAME: "
4008 "\"foo.\0\x1\v.Bar.foo\" contains null character.\nbar.proto: "
4009 "foo.\0\x1\v.Bar: NAME: \"foo.\0\x1\v.Bar\" contains null "
4010 "character.\n"));
4011 }
4012
TEST_F(ValidationErrorTest,NullCharFileName)4013 TEST_F(ValidationErrorTest, NullCharFileName) {
4014 BuildFileWithErrors(
4015 "name: \"bar\\000\\001\\013.proto\" "
4016 "package: \"outer.foo\"",
4017 STATIC_STR("bar\0\x1\v.proto: bar\0\x1\v.proto: NAME: "
4018 "\"bar\0\x1\v.proto\" contains null character.\n"));
4019 }
4020
TEST_F(ValidationErrorTest,NullCharPackageName)4021 TEST_F(ValidationErrorTest, NullCharPackageName) {
4022 BuildFileWithErrors(
4023 "name: \"bar.proto\" "
4024 "package: \"\\000\\001\\013.\"",
4025 STATIC_STR("bar.proto: \0\x1\v.: NAME: \"\0\x1\v.\" contains null "
4026 "character.\n"));
4027 }
4028
TEST_F(ValidationErrorTest,MissingFileName)4029 TEST_F(ValidationErrorTest, MissingFileName) {
4030 BuildFileWithErrors("",
4031
4032 ": : OTHER: Missing field: FileDescriptorProto.name.\n");
4033 }
4034
TEST_F(ValidationErrorTest,DupeDependency)4035 TEST_F(ValidationErrorTest, DupeDependency) {
4036 BuildFile("name: \"foo.proto\"");
4037 BuildFileWithErrors(
4038 "name: \"bar.proto\" "
4039 "dependency: \"foo.proto\" "
4040 "dependency: \"foo.proto\" ",
4041
4042 "bar.proto: foo.proto: IMPORT: Import \"foo.proto\" was listed twice.\n");
4043 }
4044
TEST_F(ValidationErrorTest,UnknownDependency)4045 TEST_F(ValidationErrorTest, UnknownDependency) {
4046 BuildFileWithErrors(
4047 "name: \"bar.proto\" "
4048 "dependency: \"foo.proto\" ",
4049
4050 "bar.proto: foo.proto: IMPORT: Import \"foo.proto\" has not been "
4051 "loaded.\n");
4052 }
4053
TEST_F(ValidationErrorTest,InvalidPublicDependencyIndex)4054 TEST_F(ValidationErrorTest, InvalidPublicDependencyIndex) {
4055 BuildFile("name: \"foo.proto\"");
4056 BuildFileWithErrors(
4057 "name: \"bar.proto\" "
4058 "dependency: \"foo.proto\" "
4059 "public_dependency: 1",
4060 "bar.proto: bar.proto: OTHER: Invalid public dependency index.\n");
4061 }
4062
TEST_F(ValidationErrorTest,ForeignUnimportedPackageNoCrash)4063 TEST_F(ValidationErrorTest, ForeignUnimportedPackageNoCrash) {
4064 // Used to crash: If we depend on a non-existent file and then refer to a
4065 // package defined in a file that we didn't import, and that package is
4066 // nested within a parent package which this file is also in, and we don't
4067 // include that parent package in the name (i.e. we do a relative lookup)...
4068 // Yes, really.
4069 BuildFile(
4070 "name: 'foo.proto' "
4071 "package: 'outer.foo' ");
4072 BuildFileWithErrors(
4073 "name: 'bar.proto' "
4074 "dependency: 'baz.proto' "
4075 "package: 'outer.bar' "
4076 "message_type { "
4077 " name: 'Bar' "
4078 " field { name:'bar' number:1 label:LABEL_OPTIONAL type_name:'foo.Foo' }"
4079 "}",
4080
4081 "bar.proto: baz.proto: IMPORT: Import \"baz.proto\" has not been "
4082 "loaded.\n"
4083 "bar.proto: outer.bar.Bar.bar: TYPE: \"outer.foo\" seems to be defined "
4084 "in "
4085 "\"foo.proto\", which is not imported by \"bar.proto\". To use it here, "
4086 "please add the necessary import.\n");
4087 }
4088
TEST_F(ValidationErrorTest,DupeFile)4089 TEST_F(ValidationErrorTest, DupeFile) {
4090 BuildFile(
4091 "name: \"foo.proto\" "
4092 "message_type { name: \"Foo\" }");
4093 // Note: We should *not* get redundant errors about "Foo" already being
4094 // defined.
4095 BuildFileWithErrors(
4096 "name: \"foo.proto\" "
4097 "message_type { name: \"Foo\" } "
4098 // Add another type so that the files aren't identical (in which case
4099 // there would be no error).
4100 "enum_type { name: \"Bar\" }",
4101
4102 "foo.proto: foo.proto: OTHER: A file with this name is already in the "
4103 "pool.\n");
4104 }
4105
TEST_F(ValidationErrorTest,FieldInExtensionRange)4106 TEST_F(ValidationErrorTest, FieldInExtensionRange) {
4107 BuildFileWithErrors(
4108 "name: \"foo.proto\" "
4109 "message_type {"
4110 " name: \"Foo\""
4111 " field { name: \"foo\" number: 9 label:LABEL_OPTIONAL type:TYPE_INT32 "
4112 "}"
4113 " field { name: \"bar\" number: 10 label:LABEL_OPTIONAL type:TYPE_INT32 "
4114 "}"
4115 " field { name: \"baz\" number: 19 label:LABEL_OPTIONAL type:TYPE_INT32 "
4116 "}"
4117 " field { name: \"qux\" number: 20 label:LABEL_OPTIONAL type:TYPE_INT32 "
4118 "}"
4119 " extension_range { start: 10 end: 20 }"
4120 "}",
4121
4122 "foo.proto: Foo.bar: NUMBER: Extension range 10 to 19 includes field "
4123 "\"bar\" (10).\n"
4124 "foo.proto: Foo.baz: NUMBER: Extension range 10 to 19 includes field "
4125 "\"baz\" (19).\n");
4126 }
4127
TEST_F(ValidationErrorTest,OverlappingExtensionRanges)4128 TEST_F(ValidationErrorTest, OverlappingExtensionRanges) {
4129 BuildFileWithErrors(
4130 "name: \"foo.proto\" "
4131 "message_type {"
4132 " name: \"Foo\""
4133 " extension_range { start: 10 end: 20 }"
4134 " extension_range { start: 20 end: 30 }"
4135 " extension_range { start: 19 end: 21 }"
4136 "}",
4137
4138 "foo.proto: Foo: NUMBER: Extension range 19 to 20 overlaps with "
4139 "already-defined range 10 to 19.\n"
4140 "foo.proto: Foo: NUMBER: Extension range 19 to 20 overlaps with "
4141 "already-defined range 20 to 29.\n");
4142 }
4143
TEST_F(ValidationErrorTest,ReservedFieldError)4144 TEST_F(ValidationErrorTest, ReservedFieldError) {
4145 BuildFileWithErrors(
4146 "name: \"foo.proto\" "
4147 "message_type {"
4148 " name: \"Foo\""
4149 " field { name: \"foo\" number: 15 label:LABEL_OPTIONAL type:TYPE_INT32 "
4150 "}"
4151 " reserved_range { start: 10 end: 20 }"
4152 "}",
4153
4154 "foo.proto: Foo.foo: NUMBER: Field \"foo\" uses reserved number 15.\n");
4155 }
4156
TEST_F(ValidationErrorTest,ReservedExtensionRangeError)4157 TEST_F(ValidationErrorTest, ReservedExtensionRangeError) {
4158 BuildFileWithErrors(
4159 "name: \"foo.proto\" "
4160 "message_type {"
4161 " name: \"Foo\""
4162 " extension_range { start: 10 end: 20 }"
4163 " reserved_range { start: 5 end: 15 }"
4164 "}",
4165
4166 "foo.proto: Foo: NUMBER: Extension range 10 to 19"
4167 " overlaps with reserved range 5 to 14.\n");
4168 }
4169
TEST_F(ValidationErrorTest,ReservedExtensionRangeAdjacent)4170 TEST_F(ValidationErrorTest, ReservedExtensionRangeAdjacent) {
4171 BuildFile(
4172 "name: \"foo.proto\" "
4173 "message_type {"
4174 " name: \"Foo\""
4175 " extension_range { start: 10 end: 20 }"
4176 " reserved_range { start: 5 end: 10 }"
4177 "}");
4178 }
4179
TEST_F(ValidationErrorTest,ReservedRangeOverlap)4180 TEST_F(ValidationErrorTest, ReservedRangeOverlap) {
4181 BuildFileWithErrors(
4182 "name: \"foo.proto\" "
4183 "message_type {"
4184 " name: \"Foo\""
4185 " reserved_range { start: 10 end: 20 }"
4186 " reserved_range { start: 5 end: 15 }"
4187 "}",
4188
4189 "foo.proto: Foo: NUMBER: Reserved range 5 to 14"
4190 " overlaps with already-defined range 10 to 19.\n");
4191 }
4192
TEST_F(ValidationErrorTest,ReservedNameError)4193 TEST_F(ValidationErrorTest, ReservedNameError) {
4194 BuildFileWithErrors(
4195 "name: \"foo.proto\" "
4196 "message_type {"
4197 " name: \"Foo\""
4198 " field { name: \"foo\" number: 15 label:LABEL_OPTIONAL type:TYPE_INT32 "
4199 "}"
4200 " field { name: \"bar\" number: 16 label:LABEL_OPTIONAL type:TYPE_INT32 "
4201 "}"
4202 " field { name: \"baz\" number: 17 label:LABEL_OPTIONAL type:TYPE_INT32 "
4203 "}"
4204 " reserved_name: \"foo\""
4205 " reserved_name: \"bar\""
4206 "}",
4207
4208 "foo.proto: Foo.foo: NAME: Field name \"foo\" is reserved.\n"
4209 "foo.proto: Foo.bar: NAME: Field name \"bar\" is reserved.\n");
4210 }
4211
TEST_F(ValidationErrorTest,ReservedNameRedundant)4212 TEST_F(ValidationErrorTest, ReservedNameRedundant) {
4213 BuildFileWithErrors(
4214 "name: \"foo.proto\" "
4215 "message_type {"
4216 " name: \"Foo\""
4217 " reserved_name: \"foo\""
4218 " reserved_name: \"foo\""
4219 "}",
4220
4221 "foo.proto: foo: NAME: Field name \"foo\" is reserved multiple times.\n");
4222 }
4223
TEST_F(ValidationErrorTest,ReservedFieldsDebugString)4224 TEST_F(ValidationErrorTest, ReservedFieldsDebugString) {
4225 const FileDescriptor* file = BuildFile(
4226 "name: \"foo.proto\" "
4227 "message_type {"
4228 " name: \"Foo\""
4229 " reserved_name: \"foo\""
4230 " reserved_name: \"bar\""
4231 " reserved_range { start: 5 end: 6 }"
4232 " reserved_range { start: 10 end: 20 }"
4233 "}");
4234
4235 ASSERT_EQ(
4236 "syntax = \"proto2\";\n\n"
4237 "message Foo {\n"
4238 " reserved 5, 10 to 19;\n"
4239 " reserved \"foo\", \"bar\";\n"
4240 "}\n\n",
4241 file->DebugString());
4242 }
4243
TEST_F(ValidationErrorTest,DebugStringReservedRangeMax)4244 TEST_F(ValidationErrorTest, DebugStringReservedRangeMax) {
4245 const FileDescriptor* file = BuildFile(strings::Substitute(
4246 "name: \"foo.proto\" "
4247 "enum_type { "
4248 " name: \"Bar\""
4249 " value { name:\"BAR\" number:1 }"
4250 " reserved_range { start: 5 end: $0 }"
4251 "}"
4252 "message_type {"
4253 " name: \"Foo\""
4254 " reserved_range { start: 5 end: $1 }"
4255 "}",
4256 std::numeric_limits<int>::max(), FieldDescriptor::kMaxNumber + 1));
4257
4258 ASSERT_EQ(
4259 "syntax = \"proto2\";\n\n"
4260 "enum Bar {\n"
4261 " BAR = 1;\n"
4262 " reserved 5 to max;\n"
4263 "}\n\n"
4264 "message Foo {\n"
4265 " reserved 5 to max;\n"
4266 "}\n\n",
4267 file->DebugString());
4268 }
4269
TEST_F(ValidationErrorTest,EnumReservedFieldError)4270 TEST_F(ValidationErrorTest, EnumReservedFieldError) {
4271 BuildFileWithErrors(
4272 "name: \"foo.proto\" "
4273 "enum_type {"
4274 " name: \"Foo\""
4275 " value { name:\"BAR\" number:15 }"
4276 " reserved_range { start: 10 end: 20 }"
4277 "}",
4278
4279 "foo.proto: BAR: NUMBER: Enum value \"BAR\" uses reserved number 15.\n");
4280 }
4281
TEST_F(ValidationErrorTest,EnumNegativeReservedFieldError)4282 TEST_F(ValidationErrorTest, EnumNegativeReservedFieldError) {
4283 BuildFileWithErrors(
4284 "name: \"foo.proto\" "
4285 "enum_type {"
4286 " name: \"Foo\""
4287 " value { name:\"BAR\" number:-15 }"
4288 " reserved_range { start: -20 end: -10 }"
4289 "}",
4290
4291 "foo.proto: BAR: NUMBER: Enum value \"BAR\" uses reserved number -15.\n");
4292 }
4293
TEST_F(ValidationErrorTest,EnumReservedRangeOverlap)4294 TEST_F(ValidationErrorTest, EnumReservedRangeOverlap) {
4295 BuildFileWithErrors(
4296 "name: \"foo.proto\" "
4297 "enum_type {"
4298 " name: \"Foo\""
4299 " value { name:\"BAR\" number:0 }"
4300 " reserved_range { start: 10 end: 20 }"
4301 " reserved_range { start: 5 end: 15 }"
4302 "}",
4303
4304 "foo.proto: Foo: NUMBER: Reserved range 5 to 15"
4305 " overlaps with already-defined range 10 to 20.\n");
4306 }
4307
TEST_F(ValidationErrorTest,EnumReservedRangeOverlapByOne)4308 TEST_F(ValidationErrorTest, EnumReservedRangeOverlapByOne) {
4309 BuildFileWithErrors(
4310 "name: \"foo.proto\" "
4311 "enum_type {"
4312 " name: \"Foo\""
4313 " value { name:\"BAR\" number:0 }"
4314 " reserved_range { start: 10 end: 20 }"
4315 " reserved_range { start: 5 end: 10 }"
4316 "}",
4317
4318 "foo.proto: Foo: NUMBER: Reserved range 5 to 10"
4319 " overlaps with already-defined range 10 to 20.\n");
4320 }
4321
TEST_F(ValidationErrorTest,EnumNegativeReservedRangeOverlap)4322 TEST_F(ValidationErrorTest, EnumNegativeReservedRangeOverlap) {
4323 BuildFileWithErrors(
4324 "name: \"foo.proto\" "
4325 "enum_type {"
4326 " name: \"Foo\""
4327 " value { name:\"BAR\" number:0 }"
4328 " reserved_range { start: -20 end: -10 }"
4329 " reserved_range { start: -15 end: -5 }"
4330 "}",
4331
4332 "foo.proto: Foo: NUMBER: Reserved range -15 to -5"
4333 " overlaps with already-defined range -20 to -10.\n");
4334 }
4335
TEST_F(ValidationErrorTest,EnumMixedReservedRangeOverlap)4336 TEST_F(ValidationErrorTest, EnumMixedReservedRangeOverlap) {
4337 BuildFileWithErrors(
4338 "name: \"foo.proto\" "
4339 "enum_type {"
4340 " name: \"Foo\""
4341 " value { name:\"BAR\" number:20 }"
4342 " reserved_range { start: -20 end: 10 }"
4343 " reserved_range { start: -15 end: 5 }"
4344 "}",
4345
4346 "foo.proto: Foo: NUMBER: Reserved range -15 to 5"
4347 " overlaps with already-defined range -20 to 10.\n");
4348 }
4349
TEST_F(ValidationErrorTest,EnumMixedReservedRangeOverlap2)4350 TEST_F(ValidationErrorTest, EnumMixedReservedRangeOverlap2) {
4351 BuildFileWithErrors(
4352 "name: \"foo.proto\" "
4353 "enum_type {"
4354 " name: \"Foo\""
4355 " value { name:\"BAR\" number:20 }"
4356 " reserved_range { start: -20 end: 10 }"
4357 " reserved_range { start: 10 end: 10 }"
4358 "}",
4359
4360 "foo.proto: Foo: NUMBER: Reserved range 10 to 10"
4361 " overlaps with already-defined range -20 to 10.\n");
4362 }
4363
TEST_F(ValidationErrorTest,EnumReservedRangeStartGreaterThanEnd)4364 TEST_F(ValidationErrorTest, EnumReservedRangeStartGreaterThanEnd) {
4365 BuildFileWithErrors(
4366 "name: \"foo.proto\" "
4367 "enum_type {"
4368 " name: \"Foo\""
4369 " value { name:\"BAR\" number:20 }"
4370 " reserved_range { start: 11 end: 10 }"
4371 "}",
4372
4373 "foo.proto: Foo: NUMBER: Reserved range end number must be greater"
4374 " than start number.\n");
4375 }
4376
TEST_F(ValidationErrorTest,EnumReservedNameError)4377 TEST_F(ValidationErrorTest, EnumReservedNameError) {
4378 BuildFileWithErrors(
4379 "name: \"foo.proto\" "
4380 "enum_type {"
4381 " name: \"Foo\""
4382 " value { name:\"FOO\" number:15 }"
4383 " value { name:\"BAR\" number:15 }"
4384 " reserved_name: \"FOO\""
4385 " reserved_name: \"BAR\""
4386 "}",
4387
4388 "foo.proto: FOO: NAME: Enum value \"FOO\" is reserved.\n"
4389 "foo.proto: BAR: NAME: Enum value \"BAR\" is reserved.\n");
4390 }
4391
TEST_F(ValidationErrorTest,EnumReservedNameRedundant)4392 TEST_F(ValidationErrorTest, EnumReservedNameRedundant) {
4393 BuildFileWithErrors(
4394 "name: \"foo.proto\" "
4395 "enum_type {"
4396 " name: \"Foo\""
4397 " value { name:\"FOO\" number:15 }"
4398 " reserved_name: \"foo\""
4399 " reserved_name: \"foo\""
4400 "}",
4401
4402 "foo.proto: foo: NAME: Enum value \"foo\" is reserved multiple times.\n");
4403 }
4404
TEST_F(ValidationErrorTest,EnumReservedFieldsDebugString)4405 TEST_F(ValidationErrorTest, EnumReservedFieldsDebugString) {
4406 const FileDescriptor* file = BuildFile(
4407 "name: \"foo.proto\" "
4408 "enum_type {"
4409 " name: \"Foo\""
4410 " value { name:\"FOO\" number:3 }"
4411 " reserved_name: \"foo\""
4412 " reserved_name: \"bar\""
4413 " reserved_range { start: -6 end: -6 }"
4414 " reserved_range { start: -5 end: -4 }"
4415 " reserved_range { start: -1 end: 1 }"
4416 " reserved_range { start: 5 end: 5 }"
4417 " reserved_range { start: 10 end: 19 }"
4418 "}");
4419
4420 ASSERT_EQ(
4421 "syntax = \"proto2\";\n\n"
4422 "enum Foo {\n"
4423 " FOO = 3;\n"
4424 " reserved -6, -5 to -4, -1 to 1, 5, 10 to 19;\n"
4425 " reserved \"foo\", \"bar\";\n"
4426 "}\n\n",
4427 file->DebugString());
4428 }
4429
TEST_F(ValidationErrorTest,InvalidDefaults)4430 TEST_F(ValidationErrorTest, InvalidDefaults) {
4431 BuildFileWithErrors(
4432 "name: \"foo.proto\" "
4433 "message_type {"
4434 " name: \"Foo\""
4435
4436 // Invalid number.
4437 " field { name: \"foo\" number: 1 label: LABEL_OPTIONAL type: TYPE_INT32"
4438 " default_value: \"abc\" }"
4439
4440 // Empty default value.
4441 " field { name: \"bar\" number: 2 label: LABEL_OPTIONAL type: TYPE_INT32"
4442 " default_value: \"\" }"
4443
4444 // Invalid boolean.
4445 " field { name: \"baz\" number: 3 label: LABEL_OPTIONAL type: TYPE_BOOL"
4446 " default_value: \"abc\" }"
4447
4448 // Messages can't have defaults.
4449 " field { name: \"qux\" number: 4 label: LABEL_OPTIONAL type: "
4450 "TYPE_MESSAGE"
4451 " default_value: \"abc\" type_name: \"Foo\" }"
4452
4453 // Same thing, but we don't know that this field has message type until
4454 // we look up the type name.
4455 " field { name: \"quux\" number: 5 label: LABEL_OPTIONAL"
4456 " default_value: \"abc\" type_name: \"Foo\" }"
4457
4458 // Repeateds can't have defaults.
4459 " field { name: \"corge\" number: 6 label: LABEL_REPEATED type: "
4460 "TYPE_INT32"
4461 " default_value: \"1\" }"
4462 "}",
4463
4464 "foo.proto: Foo.foo: DEFAULT_VALUE: Couldn't parse default value "
4465 "\"abc\".\n"
4466 "foo.proto: Foo.bar: DEFAULT_VALUE: Couldn't parse default value \"\".\n"
4467 "foo.proto: Foo.baz: DEFAULT_VALUE: Boolean default must be true or "
4468 "false.\n"
4469 "foo.proto: Foo.qux: DEFAULT_VALUE: Messages can't have default values.\n"
4470 "foo.proto: Foo.corge: DEFAULT_VALUE: Repeated fields can't have default "
4471 "values.\n"
4472 // This ends up being reported later because the error is detected at
4473 // cross-linking time.
4474 "foo.proto: Foo.quux: DEFAULT_VALUE: Messages can't have default "
4475 "values.\n");
4476 }
4477
TEST_F(ValidationErrorTest,NegativeFieldNumber)4478 TEST_F(ValidationErrorTest, NegativeFieldNumber) {
4479 BuildFileWithErrors(
4480 "name: \"foo.proto\" "
4481 "message_type {"
4482 " name: \"Foo\""
4483 " field { name: \"foo\" number: -1 label:LABEL_OPTIONAL type:TYPE_INT32 "
4484 "}"
4485 "}",
4486
4487 "foo.proto: Foo.foo: NUMBER: Field numbers must be positive integers.\n");
4488 }
4489
TEST_F(ValidationErrorTest,HugeFieldNumber)4490 TEST_F(ValidationErrorTest, HugeFieldNumber) {
4491 BuildFileWithErrors(
4492 "name: \"foo.proto\" "
4493 "message_type {"
4494 " name: \"Foo\""
4495 " field { name: \"foo\" number: 0x70000000 "
4496 " label:LABEL_OPTIONAL type:TYPE_INT32 }"
4497 "}",
4498
4499 "foo.proto: Foo.foo: NUMBER: Field numbers cannot be greater than "
4500 "536870911.\n");
4501 }
4502
TEST_F(ValidationErrorTest,ReservedFieldNumber)4503 TEST_F(ValidationErrorTest, ReservedFieldNumber) {
4504 BuildFileWithErrors(
4505 "name: \"foo.proto\" "
4506 "message_type {"
4507 " name: \"Foo\""
4508 " field {name:\"foo\" number: 18999 label:LABEL_OPTIONAL "
4509 "type:TYPE_INT32 }"
4510 " field {name:\"bar\" number: 19000 label:LABEL_OPTIONAL "
4511 "type:TYPE_INT32 }"
4512 " field {name:\"baz\" number: 19999 label:LABEL_OPTIONAL "
4513 "type:TYPE_INT32 }"
4514 " field {name:\"qux\" number: 20000 label:LABEL_OPTIONAL "
4515 "type:TYPE_INT32 }"
4516 "}",
4517
4518 "foo.proto: Foo.bar: NUMBER: Field numbers 19000 through 19999 are "
4519 "reserved for the protocol buffer library implementation.\n"
4520 "foo.proto: Foo.baz: NUMBER: Field numbers 19000 through 19999 are "
4521 "reserved for the protocol buffer library implementation.\n");
4522 }
4523
TEST_F(ValidationErrorTest,ExtensionMissingExtendee)4524 TEST_F(ValidationErrorTest, ExtensionMissingExtendee) {
4525 BuildFileWithErrors(
4526 "name: \"foo.proto\" "
4527 "message_type {"
4528 " name: \"Foo\""
4529 " extension { name: \"foo\" number: 1 label: LABEL_OPTIONAL"
4530 " type_name: \"Foo\" }"
4531 "}",
4532
4533 "foo.proto: Foo.foo: EXTENDEE: FieldDescriptorProto.extendee not set for "
4534 "extension field.\n");
4535 }
4536
TEST_F(ValidationErrorTest,NonExtensionWithExtendee)4537 TEST_F(ValidationErrorTest, NonExtensionWithExtendee) {
4538 BuildFileWithErrors(
4539 "name: \"foo.proto\" "
4540 "message_type {"
4541 " name: \"Bar\""
4542 " extension_range { start: 1 end: 2 }"
4543 "}"
4544 "message_type {"
4545 " name: \"Foo\""
4546 " field { name: \"foo\" number: 1 label: LABEL_OPTIONAL"
4547 " type_name: \"Foo\" extendee: \"Bar\" }"
4548 "}",
4549
4550 "foo.proto: Foo.foo: EXTENDEE: FieldDescriptorProto.extendee set for "
4551 "non-extension field.\n");
4552 }
4553
TEST_F(ValidationErrorTest,FieldOneofIndexTooLarge)4554 TEST_F(ValidationErrorTest, FieldOneofIndexTooLarge) {
4555 BuildFileWithErrors(
4556 "name: \"foo.proto\" "
4557 "message_type {"
4558 " name: \"Foo\""
4559 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_INT32 "
4560 " oneof_index: 1 }"
4561 " field { name:\"dummy\" number:2 label:LABEL_OPTIONAL type:TYPE_INT32 "
4562 " oneof_index: 0 }"
4563 " oneof_decl { name:\"bar\" }"
4564 "}",
4565
4566 "foo.proto: Foo.foo: TYPE: FieldDescriptorProto.oneof_index 1 is out of "
4567 "range for type \"Foo\".\n");
4568 }
4569
TEST_F(ValidationErrorTest,FieldOneofIndexNegative)4570 TEST_F(ValidationErrorTest, FieldOneofIndexNegative) {
4571 BuildFileWithErrors(
4572 "name: \"foo.proto\" "
4573 "message_type {"
4574 " name: \"Foo\""
4575 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_INT32 "
4576 " oneof_index: -1 }"
4577 " field { name:\"dummy\" number:2 label:LABEL_OPTIONAL type:TYPE_INT32 "
4578 " oneof_index: 0 }"
4579 " oneof_decl { name:\"bar\" }"
4580 "}",
4581
4582 "foo.proto: Foo.foo: TYPE: FieldDescriptorProto.oneof_index -1 is out "
4583 "of "
4584 "range for type \"Foo\".\n");
4585 }
4586
TEST_F(ValidationErrorTest,OneofFieldsConsecutiveDefinition)4587 TEST_F(ValidationErrorTest, OneofFieldsConsecutiveDefinition) {
4588 // Fields belonging to the same oneof must be defined consecutively.
4589 BuildFileWithErrors(
4590 "name: \"foo.proto\" "
4591 "message_type {"
4592 " name: \"Foo\""
4593 " field { name:\"foo1\" number: 1 label:LABEL_OPTIONAL type:TYPE_INT32 "
4594 " oneof_index: 0 }"
4595 " field { name:\"bar\" number: 2 label:LABEL_OPTIONAL type:TYPE_INT32 }"
4596 " field { name:\"foo2\" number: 3 label:LABEL_OPTIONAL type:TYPE_INT32 "
4597 " oneof_index: 0 }"
4598 " oneof_decl { name:\"foos\" }"
4599 "}",
4600
4601 "foo.proto: Foo.bar: TYPE: Fields in the same oneof must be defined "
4602 "consecutively. \"bar\" cannot be defined before the completion of the "
4603 "\"foos\" oneof definition.\n");
4604
4605 // Prevent interleaved fields, which belong to different oneofs.
4606 BuildFileWithErrors(
4607 "name: \"foo2.proto\" "
4608 "message_type {"
4609 " name: \"Foo2\""
4610 " field { name:\"foo1\" number: 1 label:LABEL_OPTIONAL type:TYPE_INT32 "
4611 " oneof_index: 0 }"
4612 " field { name:\"bar1\" number: 2 label:LABEL_OPTIONAL type:TYPE_INT32 "
4613 " oneof_index: 1 }"
4614 " field { name:\"foo2\" number: 3 label:LABEL_OPTIONAL type:TYPE_INT32 "
4615 " oneof_index: 0 }"
4616 " field { name:\"bar2\" number: 4 label:LABEL_OPTIONAL type:TYPE_INT32 "
4617 " oneof_index: 1 }"
4618 " oneof_decl { name:\"foos\" }"
4619 " oneof_decl { name:\"bars\" }"
4620 "}",
4621 "foo2.proto: Foo2.bar1: TYPE: Fields in the same oneof must be defined "
4622 "consecutively. \"bar1\" cannot be defined before the completion of the "
4623 "\"foos\" oneof definition.\n"
4624 "foo2.proto: Foo2.foo2: TYPE: Fields in the same oneof must be defined "
4625 "consecutively. \"foo2\" cannot be defined before the completion of the "
4626 "\"bars\" oneof definition.\n");
4627
4628 // Another case for normal fields and different oneof fields interleave.
4629 BuildFileWithErrors(
4630 "name: \"foo3.proto\" "
4631 "message_type {"
4632 " name: \"Foo3\""
4633 " field { name:\"foo1\" number: 1 label:LABEL_OPTIONAL type:TYPE_INT32 "
4634 " oneof_index: 0 }"
4635 " field { name:\"bar1\" number: 2 label:LABEL_OPTIONAL type:TYPE_INT32 "
4636 " oneof_index: 1 }"
4637 " field { name:\"baz\" number: 3 label:LABEL_OPTIONAL type:TYPE_INT32 }"
4638 " field { name:\"foo2\" number: 4 label:LABEL_OPTIONAL type:TYPE_INT32 "
4639 " oneof_index: 0 }"
4640 " oneof_decl { name:\"foos\" }"
4641 " oneof_decl { name:\"bars\" }"
4642 "}",
4643 "foo3.proto: Foo3.baz: TYPE: Fields in the same oneof must be defined "
4644 "consecutively. \"baz\" cannot be defined before the completion of the "
4645 "\"foos\" oneof definition.\n");
4646 }
4647
TEST_F(ValidationErrorTest,FieldNumberConflict)4648 TEST_F(ValidationErrorTest, FieldNumberConflict) {
4649 BuildFileWithErrors(
4650 "name: \"foo.proto\" "
4651 "message_type {"
4652 " name: \"Foo\""
4653 " field { name: \"foo\" number: 1 label:LABEL_OPTIONAL type:TYPE_INT32 }"
4654 " field { name: \"bar\" number: 1 label:LABEL_OPTIONAL type:TYPE_INT32 }"
4655 "}",
4656
4657 "foo.proto: Foo.bar: NUMBER: Field number 1 has already been used in "
4658 "\"Foo\" by field \"foo\".\n");
4659 }
4660
TEST_F(ValidationErrorTest,BadMessageSetExtensionType)4661 TEST_F(ValidationErrorTest, BadMessageSetExtensionType) {
4662 BuildFileWithErrors(
4663 "name: \"foo.proto\" "
4664 "message_type {"
4665 " name: \"MessageSet\""
4666 " options { message_set_wire_format: true }"
4667 " extension_range { start: 4 end: 5 }"
4668 "}"
4669 "message_type {"
4670 " name: \"Foo\""
4671 " extension { name:\"foo\" number:4 label:LABEL_OPTIONAL type:TYPE_INT32"
4672 " extendee: \"MessageSet\" }"
4673 "}",
4674
4675 "foo.proto: Foo.foo: TYPE: Extensions of MessageSets must be optional "
4676 "messages.\n");
4677 }
4678
TEST_F(ValidationErrorTest,BadMessageSetExtensionLabel)4679 TEST_F(ValidationErrorTest, BadMessageSetExtensionLabel) {
4680 BuildFileWithErrors(
4681 "name: \"foo.proto\" "
4682 "message_type {"
4683 " name: \"MessageSet\""
4684 " options { message_set_wire_format: true }"
4685 " extension_range { start: 4 end: 5 }"
4686 "}"
4687 "message_type {"
4688 " name: \"Foo\""
4689 " extension { name:\"foo\" number:4 label:LABEL_REPEATED "
4690 "type:TYPE_MESSAGE"
4691 " type_name: \"Foo\" extendee: \"MessageSet\" }"
4692 "}",
4693
4694 "foo.proto: Foo.foo: TYPE: Extensions of MessageSets must be optional "
4695 "messages.\n");
4696 }
4697
TEST_F(ValidationErrorTest,FieldInMessageSet)4698 TEST_F(ValidationErrorTest, FieldInMessageSet) {
4699 BuildFileWithErrors(
4700 "name: \"foo.proto\" "
4701 "message_type {"
4702 " name: \"Foo\""
4703 " options { message_set_wire_format: true }"
4704 " field { name: \"foo\" number: 1 label:LABEL_OPTIONAL type:TYPE_INT32 }"
4705 "}",
4706
4707 "foo.proto: Foo.foo: NAME: MessageSets cannot have fields, only "
4708 "extensions.\n");
4709 }
4710
TEST_F(ValidationErrorTest,NegativeExtensionRangeNumber)4711 TEST_F(ValidationErrorTest, NegativeExtensionRangeNumber) {
4712 BuildFileWithErrors(
4713 "name: \"foo.proto\" "
4714 "message_type {"
4715 " name: \"Foo\""
4716 " extension_range { start: -10 end: -1 }"
4717 "}",
4718
4719 "foo.proto: Foo: NUMBER: Extension numbers must be positive integers.\n");
4720 }
4721
TEST_F(ValidationErrorTest,HugeExtensionRangeNumber)4722 TEST_F(ValidationErrorTest, HugeExtensionRangeNumber) {
4723 BuildFileWithErrors(
4724 "name: \"foo.proto\" "
4725 "message_type {"
4726 " name: \"Foo\""
4727 " extension_range { start: 1 end: 0x70000000 }"
4728 "}",
4729
4730 "foo.proto: Foo: NUMBER: Extension numbers cannot be greater than "
4731 "536870911.\n");
4732 }
4733
TEST_F(ValidationErrorTest,ExtensionRangeEndBeforeStart)4734 TEST_F(ValidationErrorTest, ExtensionRangeEndBeforeStart) {
4735 BuildFileWithErrors(
4736 "name: \"foo.proto\" "
4737 "message_type {"
4738 " name: \"Foo\""
4739 " extension_range { start: 10 end: 10 }"
4740 " extension_range { start: 10 end: 5 }"
4741 "}",
4742
4743 "foo.proto: Foo: NUMBER: Extension range end number must be greater than "
4744 "start number.\n"
4745 "foo.proto: Foo: NUMBER: Extension range end number must be greater than "
4746 "start number.\n");
4747 }
4748
TEST_F(ValidationErrorTest,EmptyEnum)4749 TEST_F(ValidationErrorTest, EmptyEnum) {
4750 BuildFileWithErrors(
4751 "name: \"foo.proto\" "
4752 "enum_type { name: \"Foo\" }"
4753 // Also use the empty enum in a message to make sure there are no crashes
4754 // during validation (possible if the code attempts to derive a default
4755 // value for the field).
4756 "message_type {"
4757 " name: \"Bar\""
4758 " field { name: \"foo\" number: 1 label:LABEL_OPTIONAL "
4759 "type_name:\"Foo\" }"
4760 " field { name: \"bar\" number: 2 label:LABEL_OPTIONAL "
4761 "type_name:\"Foo\" "
4762 " default_value: \"NO_SUCH_VALUE\" }"
4763 "}",
4764
4765 "foo.proto: Foo: NAME: Enums must contain at least one value.\n"
4766 "foo.proto: Bar.bar: DEFAULT_VALUE: Enum type \"Foo\" has no value named "
4767 "\"NO_SUCH_VALUE\".\n");
4768 }
4769
TEST_F(ValidationErrorTest,UndefinedExtendee)4770 TEST_F(ValidationErrorTest, UndefinedExtendee) {
4771 BuildFileWithErrors(
4772 "name: \"foo.proto\" "
4773 "message_type {"
4774 " name: \"Foo\""
4775 " extension { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_INT32"
4776 " extendee: \"Bar\" }"
4777 "}",
4778
4779 "foo.proto: Foo.foo: EXTENDEE: \"Bar\" is not defined.\n");
4780 }
4781
TEST_F(ValidationErrorTest,NonMessageExtendee)4782 TEST_F(ValidationErrorTest, NonMessageExtendee) {
4783 BuildFileWithErrors(
4784 "name: \"foo.proto\" "
4785 "enum_type { name: \"Bar\" value { name:\"DUMMY\" number:0 } }"
4786 "message_type {"
4787 " name: \"Foo\""
4788 " extension { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_INT32"
4789 " extendee: \"Bar\" }"
4790 "}",
4791
4792 "foo.proto: Foo.foo: EXTENDEE: \"Bar\" is not a message type.\n");
4793 }
4794
TEST_F(ValidationErrorTest,NotAnExtensionNumber)4795 TEST_F(ValidationErrorTest, NotAnExtensionNumber) {
4796 BuildFileWithErrors(
4797 "name: \"foo.proto\" "
4798 "message_type {"
4799 " name: \"Bar\""
4800 "}"
4801 "message_type {"
4802 " name: \"Foo\""
4803 " extension { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_INT32"
4804 " extendee: \"Bar\" }"
4805 "}",
4806
4807 "foo.proto: Foo.foo: NUMBER: \"Bar\" does not declare 1 as an extension "
4808 "number.\n");
4809 }
4810
TEST_F(ValidationErrorTest,RequiredExtension)4811 TEST_F(ValidationErrorTest, RequiredExtension) {
4812 BuildFileWithErrors(
4813 "name: \"foo.proto\" "
4814 "message_type {"
4815 " name: \"Bar\""
4816 " extension_range { start: 1000 end: 10000 }"
4817 "}"
4818 "message_type {"
4819 " name: \"Foo\""
4820 " extension {"
4821 " name:\"foo\""
4822 " number:1000"
4823 " label:LABEL_REQUIRED"
4824 " type:TYPE_INT32"
4825 " extendee: \"Bar\""
4826 " }"
4827 "}",
4828
4829 "foo.proto: Foo.foo: TYPE: The extension Foo.foo cannot be required.\n");
4830 }
4831
TEST_F(ValidationErrorTest,UndefinedFieldType)4832 TEST_F(ValidationErrorTest, UndefinedFieldType) {
4833 BuildFileWithErrors(
4834 "name: \"foo.proto\" "
4835 "message_type {"
4836 " name: \"Foo\""
4837 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
4838 "}",
4839
4840 "foo.proto: Foo.foo: TYPE: \"Bar\" is not defined.\n");
4841 }
4842
TEST_F(ValidationErrorTest,UndefinedFieldTypeWithDefault)4843 TEST_F(ValidationErrorTest, UndefinedFieldTypeWithDefault) {
4844 // See b/12533582. Previously this failed because the default value was not
4845 // accepted by the parser, which assumed an enum type, leading to an unclear
4846 // error message. We want this input to yield a validation error instead,
4847 // since the unknown type is the primary problem.
4848 BuildFileWithErrors(
4849 "name: \"foo.proto\" "
4850 "message_type {"
4851 " name: \"Foo\""
4852 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"int\" "
4853 " default_value:\"1\" }"
4854 "}",
4855
4856 "foo.proto: Foo.foo: TYPE: \"int\" is not defined.\n");
4857 }
4858
TEST_F(ValidationErrorTest,UndefinedNestedFieldType)4859 TEST_F(ValidationErrorTest, UndefinedNestedFieldType) {
4860 BuildFileWithErrors(
4861 "name: \"foo.proto\" "
4862 "message_type {"
4863 " name: \"Foo\""
4864 " nested_type { name:\"Baz\" }"
4865 " field { name:\"foo\" number:1"
4866 " label:LABEL_OPTIONAL"
4867 " type_name:\"Foo.Baz.Bar\" }"
4868 "}",
4869
4870 "foo.proto: Foo.foo: TYPE: \"Foo.Baz.Bar\" is not defined.\n");
4871 }
4872
TEST_F(ValidationErrorTest,FieldTypeDefinedInUndeclaredDependency)4873 TEST_F(ValidationErrorTest, FieldTypeDefinedInUndeclaredDependency) {
4874 BuildFile(
4875 "name: \"bar.proto\" "
4876 "message_type { name: \"Bar\" } ");
4877
4878 BuildFileWithErrors(
4879 "name: \"foo.proto\" "
4880 "message_type {"
4881 " name: \"Foo\""
4882 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
4883 "}",
4884 "foo.proto: Foo.foo: TYPE: \"Bar\" seems to be defined in \"bar.proto\", "
4885 "which is not imported by \"foo.proto\". To use it here, please add the "
4886 "necessary import.\n");
4887 }
4888
TEST_F(ValidationErrorTest,FieldTypeDefinedInIndirectDependency)4889 TEST_F(ValidationErrorTest, FieldTypeDefinedInIndirectDependency) {
4890 // Test for hidden dependencies.
4891 //
4892 // // bar.proto
4893 // message Bar{}
4894 //
4895 // // forward.proto
4896 // import "bar.proto"
4897 //
4898 // // foo.proto
4899 // import "forward.proto"
4900 // message Foo {
4901 // optional Bar foo = 1; // Error, needs to import bar.proto explicitly.
4902 // }
4903 //
4904 BuildFile(
4905 "name: \"bar.proto\" "
4906 "message_type { name: \"Bar\" }");
4907
4908 BuildFile(
4909 "name: \"forward.proto\""
4910 "dependency: \"bar.proto\"");
4911
4912 BuildFileWithErrors(
4913 "name: \"foo.proto\" "
4914 "dependency: \"forward.proto\" "
4915 "message_type {"
4916 " name: \"Foo\""
4917 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
4918 "}",
4919 "foo.proto: Foo.foo: TYPE: \"Bar\" seems to be defined in \"bar.proto\", "
4920 "which is not imported by \"foo.proto\". To use it here, please add the "
4921 "necessary import.\n");
4922 }
4923
TEST_F(ValidationErrorTest,FieldTypeDefinedInPublicDependency)4924 TEST_F(ValidationErrorTest, FieldTypeDefinedInPublicDependency) {
4925 // Test for public dependencies.
4926 //
4927 // // bar.proto
4928 // message Bar{}
4929 //
4930 // // forward.proto
4931 // import public "bar.proto"
4932 //
4933 // // foo.proto
4934 // import "forward.proto"
4935 // message Foo {
4936 // optional Bar foo = 1; // Correct. "bar.proto" is public imported into
4937 // // forward.proto, so when "foo.proto" imports
4938 // // "forward.proto", it imports "bar.proto" too.
4939 // }
4940 //
4941 BuildFile(
4942 "name: \"bar.proto\" "
4943 "message_type { name: \"Bar\" }");
4944
4945 BuildFile(
4946 "name: \"forward.proto\""
4947 "dependency: \"bar.proto\" "
4948 "public_dependency: 0");
4949
4950 BuildFile(
4951 "name: \"foo.proto\" "
4952 "dependency: \"forward.proto\" "
4953 "message_type {"
4954 " name: \"Foo\""
4955 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
4956 "}");
4957 }
4958
TEST_F(ValidationErrorTest,FieldTypeDefinedInTransitivePublicDependency)4959 TEST_F(ValidationErrorTest, FieldTypeDefinedInTransitivePublicDependency) {
4960 // Test for public dependencies.
4961 //
4962 // // bar.proto
4963 // message Bar{}
4964 //
4965 // // forward.proto
4966 // import public "bar.proto"
4967 //
4968 // // forward2.proto
4969 // import public "forward.proto"
4970 //
4971 // // foo.proto
4972 // import "forward2.proto"
4973 // message Foo {
4974 // optional Bar foo = 1; // Correct, public imports are transitive.
4975 // }
4976 //
4977 BuildFile(
4978 "name: \"bar.proto\" "
4979 "message_type { name: \"Bar\" }");
4980
4981 BuildFile(
4982 "name: \"forward.proto\""
4983 "dependency: \"bar.proto\" "
4984 "public_dependency: 0");
4985
4986 BuildFile(
4987 "name: \"forward2.proto\""
4988 "dependency: \"forward.proto\" "
4989 "public_dependency: 0");
4990
4991 BuildFile(
4992 "name: \"foo.proto\" "
4993 "dependency: \"forward2.proto\" "
4994 "message_type {"
4995 " name: \"Foo\""
4996 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
4997 "}");
4998 }
4999
TEST_F(ValidationErrorTest,FieldTypeDefinedInPrivateDependencyOfPublicDependency)5000 TEST_F(ValidationErrorTest,
5001 FieldTypeDefinedInPrivateDependencyOfPublicDependency) {
5002 // Test for public dependencies.
5003 //
5004 // // bar.proto
5005 // message Bar{}
5006 //
5007 // // forward.proto
5008 // import "bar.proto"
5009 //
5010 // // forward2.proto
5011 // import public "forward.proto"
5012 //
5013 // // foo.proto
5014 // import "forward2.proto"
5015 // message Foo {
5016 // optional Bar foo = 1; // Error, the "bar.proto" is not public imported
5017 // // into "forward.proto", so will not be imported
5018 // // into either "forward2.proto" or "foo.proto".
5019 // }
5020 //
5021 BuildFile(
5022 "name: \"bar.proto\" "
5023 "message_type { name: \"Bar\" }");
5024
5025 BuildFile(
5026 "name: \"forward.proto\""
5027 "dependency: \"bar.proto\"");
5028
5029 BuildFile(
5030 "name: \"forward2.proto\""
5031 "dependency: \"forward.proto\" "
5032 "public_dependency: 0");
5033
5034 BuildFileWithErrors(
5035 "name: \"foo.proto\" "
5036 "dependency: \"forward2.proto\" "
5037 "message_type {"
5038 " name: \"Foo\""
5039 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
5040 "}",
5041 "foo.proto: Foo.foo: TYPE: \"Bar\" seems to be defined in \"bar.proto\", "
5042 "which is not imported by \"foo.proto\". To use it here, please add the "
5043 "necessary import.\n");
5044 }
5045
5046
TEST_F(ValidationErrorTest,SearchMostLocalFirst)5047 TEST_F(ValidationErrorTest, SearchMostLocalFirst) {
5048 // The following should produce an error that Bar.Baz is resolved but
5049 // not defined:
5050 // message Bar { message Baz {} }
5051 // message Foo {
5052 // message Bar {
5053 // // Placing "message Baz{}" here, or removing Foo.Bar altogether,
5054 // // would fix the error.
5055 // }
5056 // optional Bar.Baz baz = 1;
5057 // }
5058 // An one point the lookup code incorrectly did not produce an error in this
5059 // case, because when looking for Bar.Baz, it would try "Foo.Bar.Baz" first,
5060 // fail, and ten try "Bar.Baz" and succeed, even though "Bar" should actually
5061 // refer to the inner Bar, not the outer one.
5062 BuildFileWithErrors(
5063 "name: \"foo.proto\" "
5064 "message_type {"
5065 " name: \"Bar\""
5066 " nested_type { name: \"Baz\" }"
5067 "}"
5068 "message_type {"
5069 " name: \"Foo\""
5070 " nested_type { name: \"Bar\" }"
5071 " field { name:\"baz\" number:1 label:LABEL_OPTIONAL"
5072 " type_name:\"Bar.Baz\" }"
5073 "}",
5074
5075 "foo.proto: Foo.baz: TYPE: \"Bar.Baz\" is resolved to \"Foo.Bar.Baz\","
5076 " which is not defined. The innermost scope is searched first in name "
5077 "resolution. Consider using a leading '.'(i.e., \".Bar.Baz\") to start "
5078 "from the outermost scope.\n");
5079 }
5080
TEST_F(ValidationErrorTest,SearchMostLocalFirst2)5081 TEST_F(ValidationErrorTest, SearchMostLocalFirst2) {
5082 // This test would find the most local "Bar" first, and does, but
5083 // proceeds to find the outer one because the inner one's not an
5084 // aggregate.
5085 BuildFile(
5086 "name: \"foo.proto\" "
5087 "message_type {"
5088 " name: \"Bar\""
5089 " nested_type { name: \"Baz\" }"
5090 "}"
5091 "message_type {"
5092 " name: \"Foo\""
5093 " field { name: \"Bar\" number:1 type:TYPE_BYTES } "
5094 " field { name:\"baz\" number:2 label:LABEL_OPTIONAL"
5095 " type_name:\"Bar.Baz\" }"
5096 "}");
5097 }
5098
TEST_F(ValidationErrorTest,PackageOriginallyDeclaredInTransitiveDependent)5099 TEST_F(ValidationErrorTest, PackageOriginallyDeclaredInTransitiveDependent) {
5100 // Imagine we have the following:
5101 //
5102 // foo.proto:
5103 // package foo.bar;
5104 // bar.proto:
5105 // package foo.bar;
5106 // import "foo.proto";
5107 // message Bar {}
5108 // baz.proto:
5109 // package foo;
5110 // import "bar.proto"
5111 // message Baz { optional bar.Bar qux = 1; }
5112 //
5113 // When validating baz.proto, we will look up "bar.Bar". As part of this
5114 // lookup, we first lookup "bar" then try to find "Bar" within it. "bar"
5115 // should resolve to "foo.bar". Note, though, that "foo.bar" was originally
5116 // defined in foo.proto, which is not a direct dependency of baz.proto. The
5117 // implementation of FindSymbol() normally only returns symbols in direct
5118 // dependencies, not indirect ones. This test insures that this does not
5119 // prevent it from finding "foo.bar".
5120
5121 BuildFile(
5122 "name: \"foo.proto\" "
5123 "package: \"foo.bar\" ");
5124 BuildFile(
5125 "name: \"bar.proto\" "
5126 "package: \"foo.bar\" "
5127 "dependency: \"foo.proto\" "
5128 "message_type { name: \"Bar\" }");
5129 BuildFile(
5130 "name: \"baz.proto\" "
5131 "package: \"foo\" "
5132 "dependency: \"bar.proto\" "
5133 "message_type { "
5134 " name: \"Baz\" "
5135 " field { name:\"qux\" number:1 label:LABEL_OPTIONAL "
5136 " type_name:\"bar.Bar\" }"
5137 "}");
5138 }
5139
TEST_F(ValidationErrorTest,FieldTypeNotAType)5140 TEST_F(ValidationErrorTest, FieldTypeNotAType) {
5141 BuildFileWithErrors(
5142 "name: \"foo.proto\" "
5143 "message_type {"
5144 " name: \"Foo\""
5145 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL "
5146 " type_name:\".Foo.bar\" }"
5147 " field { name:\"bar\" number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }"
5148 "}",
5149
5150 "foo.proto: Foo.foo: TYPE: \".Foo.bar\" is not a type.\n");
5151 }
5152
TEST_F(ValidationErrorTest,RelativeFieldTypeNotAType)5153 TEST_F(ValidationErrorTest, RelativeFieldTypeNotAType) {
5154 BuildFileWithErrors(
5155 "name: \"foo.proto\" "
5156 "message_type {"
5157 " nested_type {"
5158 " name: \"Bar\""
5159 " field { name:\"Baz\" number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }"
5160 " }"
5161 " name: \"Foo\""
5162 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL "
5163 " type_name:\"Bar.Baz\" }"
5164 "}",
5165 "foo.proto: Foo.foo: TYPE: \"Bar.Baz\" is not a type.\n");
5166 }
5167
TEST_F(ValidationErrorTest,FieldTypeMayBeItsName)5168 TEST_F(ValidationErrorTest, FieldTypeMayBeItsName) {
5169 BuildFile(
5170 "name: \"foo.proto\" "
5171 "message_type {"
5172 " name: \"Bar\""
5173 "}"
5174 "message_type {"
5175 " name: \"Foo\""
5176 " field { name:\"Bar\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
5177 "}");
5178 }
5179
TEST_F(ValidationErrorTest,EnumFieldTypeIsMessage)5180 TEST_F(ValidationErrorTest, EnumFieldTypeIsMessage) {
5181 BuildFileWithErrors(
5182 "name: \"foo.proto\" "
5183 "message_type { name: \"Bar\" } "
5184 "message_type {"
5185 " name: \"Foo\""
5186 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_ENUM"
5187 " type_name:\"Bar\" }"
5188 "}",
5189
5190 "foo.proto: Foo.foo: TYPE: \"Bar\" is not an enum type.\n");
5191 }
5192
TEST_F(ValidationErrorTest,MessageFieldTypeIsEnum)5193 TEST_F(ValidationErrorTest, MessageFieldTypeIsEnum) {
5194 BuildFileWithErrors(
5195 "name: \"foo.proto\" "
5196 "enum_type { name: \"Bar\" value { name:\"DUMMY\" number:0 } } "
5197 "message_type {"
5198 " name: \"Foo\""
5199 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_MESSAGE"
5200 " type_name:\"Bar\" }"
5201 "}",
5202
5203 "foo.proto: Foo.foo: TYPE: \"Bar\" is not a message type.\n");
5204 }
5205
TEST_F(ValidationErrorTest,BadEnumDefaultValue)5206 TEST_F(ValidationErrorTest, BadEnumDefaultValue) {
5207 BuildFileWithErrors(
5208 "name: \"foo.proto\" "
5209 "enum_type { name: \"Bar\" value { name:\"DUMMY\" number:0 } } "
5210 "message_type {"
5211 " name: \"Foo\""
5212 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\""
5213 " default_value:\"NO_SUCH_VALUE\" }"
5214 "}",
5215
5216 "foo.proto: Foo.foo: DEFAULT_VALUE: Enum type \"Bar\" has no value named "
5217 "\"NO_SUCH_VALUE\".\n");
5218 }
5219
TEST_F(ValidationErrorTest,EnumDefaultValueIsInteger)5220 TEST_F(ValidationErrorTest, EnumDefaultValueIsInteger) {
5221 BuildFileWithErrors(
5222 "name: \"foo.proto\" "
5223 "enum_type { name: \"Bar\" value { name:\"DUMMY\" number:0 } } "
5224 "message_type {"
5225 " name: \"Foo\""
5226 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\""
5227 " default_value:\"0\" }"
5228 "}",
5229
5230 "foo.proto: Foo.foo: DEFAULT_VALUE: Default value for an enum field must "
5231 "be an identifier.\n");
5232 }
5233
TEST_F(ValidationErrorTest,PrimitiveWithTypeName)5234 TEST_F(ValidationErrorTest, PrimitiveWithTypeName) {
5235 BuildFileWithErrors(
5236 "name: \"foo.proto\" "
5237 "message_type {"
5238 " name: \"Foo\""
5239 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_INT32"
5240 " type_name:\"Foo\" }"
5241 "}",
5242
5243 "foo.proto: Foo.foo: TYPE: Field with primitive type has type_name.\n");
5244 }
5245
TEST_F(ValidationErrorTest,NonPrimitiveWithoutTypeName)5246 TEST_F(ValidationErrorTest, NonPrimitiveWithoutTypeName) {
5247 BuildFileWithErrors(
5248 "name: \"foo.proto\" "
5249 "message_type {"
5250 " name: \"Foo\""
5251 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_MESSAGE }"
5252 "}",
5253
5254 "foo.proto: Foo.foo: TYPE: Field with message or enum type missing "
5255 "type_name.\n");
5256 }
5257
TEST_F(ValidationErrorTest,OneofWithNoFields)5258 TEST_F(ValidationErrorTest, OneofWithNoFields) {
5259 BuildFileWithErrors(
5260 "name: \"foo.proto\" "
5261 "message_type {"
5262 " name: \"Foo\""
5263 " oneof_decl { name:\"bar\" }"
5264 "}",
5265
5266 "foo.proto: Foo.bar: NAME: Oneof must have at least one field.\n");
5267 }
5268
TEST_F(ValidationErrorTest,OneofLabelMismatch)5269 TEST_F(ValidationErrorTest, OneofLabelMismatch) {
5270 BuildFileWithErrors(
5271 "name: \"foo.proto\" "
5272 "message_type {"
5273 " name: \"Foo\""
5274 " field { name:\"foo\" number:1 label:LABEL_REPEATED type:TYPE_INT32 "
5275 " oneof_index:0 }"
5276 " oneof_decl { name:\"bar\" }"
5277 "}",
5278
5279 "foo.proto: Foo.foo: NAME: Fields of oneofs must themselves have label "
5280 "LABEL_OPTIONAL.\n");
5281 }
5282
TEST_F(ValidationErrorTest,InputTypeNotDefined)5283 TEST_F(ValidationErrorTest, InputTypeNotDefined) {
5284 BuildFileWithErrors(
5285 "name: \"foo.proto\" "
5286 "message_type { name: \"Foo\" } "
5287 "service {"
5288 " name: \"TestService\""
5289 " method { name: \"A\" input_type: \"Bar\" output_type: \"Foo\" }"
5290 "}",
5291
5292 "foo.proto: TestService.A: INPUT_TYPE: \"Bar\" is not defined.\n"
5293 );
5294 }
5295
TEST_F(ValidationErrorTest,InputTypeNotAMessage)5296 TEST_F(ValidationErrorTest, InputTypeNotAMessage) {
5297 BuildFileWithErrors(
5298 "name: \"foo.proto\" "
5299 "message_type { name: \"Foo\" } "
5300 "enum_type { name: \"Bar\" value { name:\"DUMMY\" number:0 } } "
5301 "service {"
5302 " name: \"TestService\""
5303 " method { name: \"A\" input_type: \"Bar\" output_type: \"Foo\" }"
5304 "}",
5305
5306 "foo.proto: TestService.A: INPUT_TYPE: \"Bar\" is not a message type.\n"
5307 );
5308 }
5309
TEST_F(ValidationErrorTest,OutputTypeNotDefined)5310 TEST_F(ValidationErrorTest, OutputTypeNotDefined) {
5311 BuildFileWithErrors(
5312 "name: \"foo.proto\" "
5313 "message_type { name: \"Foo\" } "
5314 "service {"
5315 " name: \"TestService\""
5316 " method { name: \"A\" input_type: \"Foo\" output_type: \"Bar\" }"
5317 "}",
5318
5319 "foo.proto: TestService.A: OUTPUT_TYPE: \"Bar\" is not defined.\n"
5320 );
5321 }
5322
TEST_F(ValidationErrorTest,OutputTypeNotAMessage)5323 TEST_F(ValidationErrorTest, OutputTypeNotAMessage) {
5324 BuildFileWithErrors(
5325 "name: \"foo.proto\" "
5326 "message_type { name: \"Foo\" } "
5327 "enum_type { name: \"Bar\" value { name:\"DUMMY\" number:0 } } "
5328 "service {"
5329 " name: \"TestService\""
5330 " method { name: \"A\" input_type: \"Foo\" output_type: \"Bar\" }"
5331 "}",
5332
5333 "foo.proto: TestService.A: OUTPUT_TYPE: \"Bar\" is not a message type.\n"
5334 );
5335 }
5336
5337
TEST_F(ValidationErrorTest,IllegalPackedField)5338 TEST_F(ValidationErrorTest, IllegalPackedField) {
5339 BuildFileWithErrors(
5340 "name: \"foo.proto\" "
5341 "message_type {\n"
5342 " name: \"Foo\""
5343 " field { name:\"packed_string\" number:1 label:LABEL_REPEATED "
5344 " type:TYPE_STRING "
5345 " options { uninterpreted_option {"
5346 " name { name_part: \"packed\" is_extension: false }"
5347 " identifier_value: \"true\" }}}\n"
5348 " field { name:\"packed_message\" number:3 label:LABEL_REPEATED "
5349 " type_name: \"Foo\""
5350 " options { uninterpreted_option {"
5351 " name { name_part: \"packed\" is_extension: false }"
5352 " identifier_value: \"true\" }}}\n"
5353 " field { name:\"optional_int32\" number: 4 label: LABEL_OPTIONAL "
5354 " type:TYPE_INT32 "
5355 " options { uninterpreted_option {"
5356 " name { name_part: \"packed\" is_extension: false }"
5357 " identifier_value: \"true\" }}}\n"
5358 "}",
5359
5360 "foo.proto: Foo.packed_string: TYPE: [packed = true] can only be "
5361 "specified for repeated primitive fields.\n"
5362 "foo.proto: Foo.packed_message: TYPE: [packed = true] can only be "
5363 "specified for repeated primitive fields.\n"
5364 "foo.proto: Foo.optional_int32: TYPE: [packed = true] can only be "
5365 "specified for repeated primitive fields.\n");
5366 }
5367
TEST_F(ValidationErrorTest,OptionWrongType)5368 TEST_F(ValidationErrorTest, OptionWrongType) {
5369 BuildFileWithErrors(
5370 "name: \"foo.proto\" "
5371 "message_type { "
5372 " name: \"TestMessage\" "
5373 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_STRING "
5374 " options { uninterpreted_option { name { name_part: \"ctype\" "
5375 " is_extension: false }"
5376 " positive_int_value: 1 }"
5377 " }"
5378 " }"
5379 "}\n",
5380
5381 "foo.proto: TestMessage.foo: OPTION_VALUE: Value must be identifier for "
5382 "enum-valued option \"google.protobuf.FieldOptions.ctype\".\n");
5383 }
5384
TEST_F(ValidationErrorTest,OptionExtendsAtomicType)5385 TEST_F(ValidationErrorTest, OptionExtendsAtomicType) {
5386 BuildFileWithErrors(
5387 "name: \"foo.proto\" "
5388 "message_type { "
5389 " name: \"TestMessage\" "
5390 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_STRING "
5391 " options { uninterpreted_option { name { name_part: \"ctype\" "
5392 " is_extension: false }"
5393 " name { name_part: \"foo\" "
5394 " is_extension: true }"
5395 " positive_int_value: 1 }"
5396 " }"
5397 " }"
5398 "}\n",
5399
5400 "foo.proto: TestMessage.foo: OPTION_NAME: Option \"ctype\" is an "
5401 "atomic type, not a message.\n");
5402 }
5403
TEST_F(ValidationErrorTest,DupOption)5404 TEST_F(ValidationErrorTest, DupOption) {
5405 BuildFileWithErrors(
5406 "name: \"foo.proto\" "
5407 "message_type { "
5408 " name: \"TestMessage\" "
5409 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_UINT32 "
5410 " options { uninterpreted_option { name { name_part: \"ctype\" "
5411 " is_extension: false }"
5412 " identifier_value: \"CORD\" }"
5413 " uninterpreted_option { name { name_part: \"ctype\" "
5414 " is_extension: false }"
5415 " identifier_value: \"CORD\" }"
5416 " }"
5417 " }"
5418 "}\n",
5419
5420 "foo.proto: TestMessage.foo: OPTION_NAME: Option \"ctype\" was "
5421 "already set.\n");
5422 }
5423
TEST_F(ValidationErrorTest,InvalidOptionName)5424 TEST_F(ValidationErrorTest, InvalidOptionName) {
5425 BuildFileWithErrors(
5426 "name: \"foo.proto\" "
5427 "message_type { "
5428 " name: \"TestMessage\" "
5429 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_BOOL "
5430 " options { uninterpreted_option { "
5431 " name { name_part: \"uninterpreted_option\" "
5432 " is_extension: false }"
5433 " positive_int_value: 1 "
5434 " }"
5435 " }"
5436 " }"
5437 "}\n",
5438
5439 "foo.proto: TestMessage.foo: OPTION_NAME: Option must not use "
5440 "reserved name \"uninterpreted_option\".\n");
5441 }
5442
TEST_F(ValidationErrorTest,RepeatedMessageOption)5443 TEST_F(ValidationErrorTest, RepeatedMessageOption) {
5444 BuildDescriptorMessagesInTestPool();
5445
5446 BuildFileWithErrors(
5447 "name: \"foo.proto\" "
5448 "dependency: \"google/protobuf/descriptor.proto\" "
5449 "message_type: { name: \"Bar\" field: { "
5450 " name: \"foo\" number: 1 label: LABEL_OPTIONAL type: TYPE_INT32 } "
5451 "} "
5452 "extension { name: \"bar\" number: 7672757 label: LABEL_REPEATED "
5453 " type: TYPE_MESSAGE type_name: \"Bar\" "
5454 " extendee: \"google.protobuf.FileOptions\" }"
5455 "options { uninterpreted_option { name { name_part: \"bar\" "
5456 " is_extension: true } "
5457 " name { name_part: \"foo\" "
5458 " is_extension: false } "
5459 " positive_int_value: 1 } }",
5460
5461 "foo.proto: foo.proto: OPTION_NAME: Option field \"(bar)\" is a "
5462 "repeated message. Repeated message options must be initialized "
5463 "using an aggregate value.\n");
5464 }
5465
TEST_F(ValidationErrorTest,ResolveUndefinedOption)5466 TEST_F(ValidationErrorTest, ResolveUndefinedOption) {
5467 // The following should produce an error that baz.bar is resolved but not
5468 // defined.
5469 // foo.proto:
5470 // package baz
5471 // import google/protobuf/descriptor.proto
5472 // message Bar { optional int32 foo = 1; }
5473 // extend FileOptions { optional Bar bar = 7672757; }
5474 //
5475 // qux.proto:
5476 // package qux.baz
5477 // option (baz.bar).foo = 1;
5478 //
5479 // Although "baz.bar" is already defined, the lookup code will try
5480 // "qux.baz.bar", since it's the match from the innermost scope, which will
5481 // cause a symbol not defined error.
5482 BuildDescriptorMessagesInTestPool();
5483
5484 BuildFile(
5485 "name: \"foo.proto\" "
5486 "package: \"baz\" "
5487 "dependency: \"google/protobuf/descriptor.proto\" "
5488 "message_type: { name: \"Bar\" field: { "
5489 " name: \"foo\" number: 1 label: LABEL_OPTIONAL type: TYPE_INT32 } "
5490 "} "
5491 "extension { name: \"bar\" number: 7672757 label: LABEL_OPTIONAL "
5492 " type: TYPE_MESSAGE type_name: \"Bar\" "
5493 " extendee: \"google.protobuf.FileOptions\" }");
5494
5495 BuildFileWithErrors(
5496 "name: \"qux.proto\" "
5497 "package: \"qux.baz\" "
5498 "options { uninterpreted_option { name { name_part: \"baz.bar\" "
5499 " is_extension: true } "
5500 " name { name_part: \"foo\" "
5501 " is_extension: false } "
5502 " positive_int_value: 1 } }",
5503
5504 "qux.proto: qux.proto: OPTION_NAME: Option \"(baz.bar)\" is resolved to "
5505 "\"(qux.baz.bar)\","
5506 " which is not defined. The innermost scope is searched first in name "
5507 "resolution. Consider using a leading '.'(i.e., \"(.baz.bar)\") to start "
5508 "from the outermost scope.\n");
5509 }
5510
TEST_F(ValidationErrorTest,UnknownOption)5511 TEST_F(ValidationErrorTest, UnknownOption) {
5512 BuildFileWithErrors(
5513 "name: \"qux.proto\" "
5514 "package: \"qux.baz\" "
5515 "options { uninterpreted_option { name { name_part: \"baaz.bar\" "
5516 " is_extension: true } "
5517 " name { name_part: \"foo\" "
5518 " is_extension: false } "
5519 " positive_int_value: 1 } }",
5520
5521 "qux.proto: qux.proto: OPTION_NAME: Option \"(baaz.bar)\" unknown. "
5522 "Ensure "
5523 "that your proto definition file imports the proto which defines the "
5524 "option.\n");
5525 }
5526
TEST_F(ValidationErrorTest,CustomOptionConflictingFieldNumber)5527 TEST_F(ValidationErrorTest, CustomOptionConflictingFieldNumber) {
5528 BuildDescriptorMessagesInTestPool();
5529
5530 BuildFileWithErrors(
5531 "name: \"foo.proto\" "
5532 "dependency: \"google/protobuf/descriptor.proto\" "
5533 "extension { name: \"foo1\" number: 7672757 label: LABEL_OPTIONAL "
5534 " type: TYPE_INT32 extendee: \"google.protobuf.FieldOptions\" }"
5535 "extension { name: \"foo2\" number: 7672757 label: LABEL_OPTIONAL "
5536 " type: TYPE_INT32 extendee: \"google.protobuf.FieldOptions\" }",
5537
5538 "foo.proto: foo2: NUMBER: Extension number 7672757 has already been used "
5539 "in \"google.protobuf.FieldOptions\" by extension \"foo1\".\n");
5540 }
5541
TEST_F(ValidationErrorTest,Int32OptionValueOutOfPositiveRange)5542 TEST_F(ValidationErrorTest, Int32OptionValueOutOfPositiveRange) {
5543 BuildDescriptorMessagesInTestPool();
5544
5545 BuildFileWithErrors(
5546 "name: \"foo.proto\" "
5547 "dependency: \"google/protobuf/descriptor.proto\" "
5548 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
5549 " type: TYPE_INT32 extendee: \"google.protobuf.FileOptions\" }"
5550 "options { uninterpreted_option { name { name_part: \"foo\" "
5551 " is_extension: true } "
5552 " positive_int_value: 0x80000000 } "
5553 "}",
5554
5555 "foo.proto: foo.proto: OPTION_VALUE: Value out of range "
5556 "for int32 option \"foo\".\n");
5557 }
5558
TEST_F(ValidationErrorTest,Int32OptionValueOutOfNegativeRange)5559 TEST_F(ValidationErrorTest, Int32OptionValueOutOfNegativeRange) {
5560 BuildDescriptorMessagesInTestPool();
5561
5562 BuildFileWithErrors(
5563 "name: \"foo.proto\" "
5564 "dependency: \"google/protobuf/descriptor.proto\" "
5565 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
5566 " type: TYPE_INT32 extendee: \"google.protobuf.FileOptions\" }"
5567 "options { uninterpreted_option { name { name_part: \"foo\" "
5568 " is_extension: true } "
5569 " negative_int_value: -0x80000001 } "
5570 "}",
5571
5572 "foo.proto: foo.proto: OPTION_VALUE: Value out of range "
5573 "for int32 option \"foo\".\n");
5574 }
5575
TEST_F(ValidationErrorTest,Int32OptionValueIsNotPositiveInt)5576 TEST_F(ValidationErrorTest, Int32OptionValueIsNotPositiveInt) {
5577 BuildDescriptorMessagesInTestPool();
5578
5579 BuildFileWithErrors(
5580 "name: \"foo.proto\" "
5581 "dependency: \"google/protobuf/descriptor.proto\" "
5582 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
5583 " type: TYPE_INT32 extendee: \"google.protobuf.FileOptions\" }"
5584 "options { uninterpreted_option { name { name_part: \"foo\" "
5585 " is_extension: true } "
5586 " string_value: \"5\" } }",
5587
5588 "foo.proto: foo.proto: OPTION_VALUE: Value must be integer "
5589 "for int32 option \"foo\".\n");
5590 }
5591
TEST_F(ValidationErrorTest,Int64OptionValueOutOfRange)5592 TEST_F(ValidationErrorTest, Int64OptionValueOutOfRange) {
5593 BuildDescriptorMessagesInTestPool();
5594
5595 BuildFileWithErrors(
5596 "name: \"foo.proto\" "
5597 "dependency: \"google/protobuf/descriptor.proto\" "
5598 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
5599 " type: TYPE_INT64 extendee: \"google.protobuf.FileOptions\" }"
5600 "options { uninterpreted_option { name { name_part: \"foo\" "
5601 " is_extension: true } "
5602 " positive_int_value: 0x8000000000000000 "
5603 "} "
5604 "}",
5605
5606 "foo.proto: foo.proto: OPTION_VALUE: Value out of range "
5607 "for int64 option \"foo\".\n");
5608 }
5609
TEST_F(ValidationErrorTest,Int64OptionValueIsNotPositiveInt)5610 TEST_F(ValidationErrorTest, Int64OptionValueIsNotPositiveInt) {
5611 BuildDescriptorMessagesInTestPool();
5612
5613 BuildFileWithErrors(
5614 "name: \"foo.proto\" "
5615 "dependency: \"google/protobuf/descriptor.proto\" "
5616 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
5617 " type: TYPE_INT64 extendee: \"google.protobuf.FileOptions\" }"
5618 "options { uninterpreted_option { name { name_part: \"foo\" "
5619 " is_extension: true } "
5620 " identifier_value: \"5\" } }",
5621
5622 "foo.proto: foo.proto: OPTION_VALUE: Value must be integer "
5623 "for int64 option \"foo\".\n");
5624 }
5625
TEST_F(ValidationErrorTest,UInt32OptionValueOutOfRange)5626 TEST_F(ValidationErrorTest, UInt32OptionValueOutOfRange) {
5627 BuildDescriptorMessagesInTestPool();
5628
5629 BuildFileWithErrors(
5630 "name: \"foo.proto\" "
5631 "dependency: \"google/protobuf/descriptor.proto\" "
5632 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
5633 " type: TYPE_UINT32 extendee: \"google.protobuf.FileOptions\" }"
5634 "options { uninterpreted_option { name { name_part: \"foo\" "
5635 " is_extension: true } "
5636 " positive_int_value: 0x100000000 } }",
5637
5638 "foo.proto: foo.proto: OPTION_VALUE: Value out of range "
5639 "for uint32 option \"foo\".\n");
5640 }
5641
TEST_F(ValidationErrorTest,UInt32OptionValueIsNotPositiveInt)5642 TEST_F(ValidationErrorTest, UInt32OptionValueIsNotPositiveInt) {
5643 BuildDescriptorMessagesInTestPool();
5644
5645 BuildFileWithErrors(
5646 "name: \"foo.proto\" "
5647 "dependency: \"google/protobuf/descriptor.proto\" "
5648 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
5649 " type: TYPE_UINT32 extendee: \"google.protobuf.FileOptions\" }"
5650 "options { uninterpreted_option { name { name_part: \"foo\" "
5651 " is_extension: true } "
5652 " double_value: -5.6 } }",
5653
5654 "foo.proto: foo.proto: OPTION_VALUE: Value must be non-negative integer "
5655 "for uint32 option \"foo\".\n");
5656 }
5657
TEST_F(ValidationErrorTest,UInt64OptionValueIsNotPositiveInt)5658 TEST_F(ValidationErrorTest, UInt64OptionValueIsNotPositiveInt) {
5659 BuildDescriptorMessagesInTestPool();
5660
5661 BuildFileWithErrors(
5662 "name: \"foo.proto\" "
5663 "dependency: \"google/protobuf/descriptor.proto\" "
5664 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
5665 " type: TYPE_UINT64 extendee: \"google.protobuf.FileOptions\" }"
5666 "options { uninterpreted_option { name { name_part: \"foo\" "
5667 " is_extension: true } "
5668 " negative_int_value: -5 } }",
5669
5670 "foo.proto: foo.proto: OPTION_VALUE: Value must be non-negative integer "
5671 "for uint64 option \"foo\".\n");
5672 }
5673
TEST_F(ValidationErrorTest,FloatOptionValueIsNotNumber)5674 TEST_F(ValidationErrorTest, FloatOptionValueIsNotNumber) {
5675 BuildDescriptorMessagesInTestPool();
5676
5677 BuildFileWithErrors(
5678 "name: \"foo.proto\" "
5679 "dependency: \"google/protobuf/descriptor.proto\" "
5680 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
5681 " type: TYPE_FLOAT extendee: \"google.protobuf.FileOptions\" }"
5682 "options { uninterpreted_option { name { name_part: \"foo\" "
5683 " is_extension: true } "
5684 " string_value: \"bar\" } }",
5685
5686 "foo.proto: foo.proto: OPTION_VALUE: Value must be number "
5687 "for float option \"foo\".\n");
5688 }
5689
TEST_F(ValidationErrorTest,DoubleOptionValueIsNotNumber)5690 TEST_F(ValidationErrorTest, DoubleOptionValueIsNotNumber) {
5691 BuildDescriptorMessagesInTestPool();
5692
5693 BuildFileWithErrors(
5694 "name: \"foo.proto\" "
5695 "dependency: \"google/protobuf/descriptor.proto\" "
5696 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
5697 " type: TYPE_DOUBLE extendee: \"google.protobuf.FileOptions\" }"
5698 "options { uninterpreted_option { name { name_part: \"foo\" "
5699 " is_extension: true } "
5700 " string_value: \"bar\" } }",
5701
5702 "foo.proto: foo.proto: OPTION_VALUE: Value must be number "
5703 "for double option \"foo\".\n");
5704 }
5705
TEST_F(ValidationErrorTest,BoolOptionValueIsNotTrueOrFalse)5706 TEST_F(ValidationErrorTest, BoolOptionValueIsNotTrueOrFalse) {
5707 BuildDescriptorMessagesInTestPool();
5708
5709 BuildFileWithErrors(
5710 "name: \"foo.proto\" "
5711 "dependency: \"google/protobuf/descriptor.proto\" "
5712 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
5713 " type: TYPE_BOOL extendee: \"google.protobuf.FileOptions\" }"
5714 "options { uninterpreted_option { name { name_part: \"foo\" "
5715 " is_extension: true } "
5716 " identifier_value: \"bar\" } }",
5717
5718 "foo.proto: foo.proto: OPTION_VALUE: Value must be \"true\" or \"false\" "
5719 "for boolean option \"foo\".\n");
5720 }
5721
TEST_F(ValidationErrorTest,EnumOptionValueIsNotIdentifier)5722 TEST_F(ValidationErrorTest, EnumOptionValueIsNotIdentifier) {
5723 BuildDescriptorMessagesInTestPool();
5724
5725 BuildFileWithErrors(
5726 "name: \"foo.proto\" "
5727 "dependency: \"google/protobuf/descriptor.proto\" "
5728 "enum_type { name: \"FooEnum\" value { name: \"BAR\" number: 1 } "
5729 " value { name: \"BAZ\" number: 2 } }"
5730 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
5731 " type: TYPE_ENUM type_name: \"FooEnum\" "
5732 " extendee: \"google.protobuf.FileOptions\" }"
5733 "options { uninterpreted_option { name { name_part: \"foo\" "
5734 " is_extension: true } "
5735 " string_value: \"QUUX\" } }",
5736
5737 "foo.proto: foo.proto: OPTION_VALUE: Value must be identifier for "
5738 "enum-valued option \"foo\".\n");
5739 }
5740
TEST_F(ValidationErrorTest,EnumOptionValueIsNotEnumValueName)5741 TEST_F(ValidationErrorTest, EnumOptionValueIsNotEnumValueName) {
5742 BuildDescriptorMessagesInTestPool();
5743
5744 BuildFileWithErrors(
5745 "name: \"foo.proto\" "
5746 "dependency: \"google/protobuf/descriptor.proto\" "
5747 "enum_type { name: \"FooEnum\" value { name: \"BAR\" number: 1 } "
5748 " value { name: \"BAZ\" number: 2 } }"
5749 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
5750 " type: TYPE_ENUM type_name: \"FooEnum\" "
5751 " extendee: \"google.protobuf.FileOptions\" }"
5752 "options { uninterpreted_option { name { name_part: \"foo\" "
5753 " is_extension: true } "
5754 " identifier_value: \"QUUX\" } }",
5755
5756 "foo.proto: foo.proto: OPTION_VALUE: Enum type \"FooEnum\" has no value "
5757 "named \"QUUX\" for option \"foo\".\n");
5758 }
5759
TEST_F(ValidationErrorTest,EnumOptionValueIsSiblingEnumValueName)5760 TEST_F(ValidationErrorTest, EnumOptionValueIsSiblingEnumValueName) {
5761 BuildDescriptorMessagesInTestPool();
5762
5763 BuildFileWithErrors(
5764 "name: \"foo.proto\" "
5765 "dependency: \"google/protobuf/descriptor.proto\" "
5766 "enum_type { name: \"FooEnum1\" value { name: \"BAR\" number: 1 } "
5767 " value { name: \"BAZ\" number: 2 } }"
5768 "enum_type { name: \"FooEnum2\" value { name: \"QUX\" number: 1 } "
5769 " value { name: \"QUUX\" number: 2 } }"
5770 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
5771 " type: TYPE_ENUM type_name: \"FooEnum1\" "
5772 " extendee: \"google.protobuf.FileOptions\" }"
5773 "options { uninterpreted_option { name { name_part: \"foo\" "
5774 " is_extension: true } "
5775 " identifier_value: \"QUUX\" } }",
5776
5777 "foo.proto: foo.proto: OPTION_VALUE: Enum type \"FooEnum1\" has no value "
5778 "named \"QUUX\" for option \"foo\". This appears to be a value from a "
5779 "sibling type.\n");
5780 }
5781
TEST_F(ValidationErrorTest,StringOptionValueIsNotString)5782 TEST_F(ValidationErrorTest, StringOptionValueIsNotString) {
5783 BuildDescriptorMessagesInTestPool();
5784
5785 BuildFileWithErrors(
5786 "name: \"foo.proto\" "
5787 "dependency: \"google/protobuf/descriptor.proto\" "
5788 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
5789 " type: TYPE_STRING extendee: \"google.protobuf.FileOptions\" }"
5790 "options { uninterpreted_option { name { name_part: \"foo\" "
5791 " is_extension: true } "
5792 " identifier_value: \"QUUX\" } }",
5793
5794 "foo.proto: foo.proto: OPTION_VALUE: Value must be quoted string "
5795 "for "
5796 "string option \"foo\".\n");
5797 }
5798
TEST_F(ValidationErrorTest,JsonNameOptionOnExtensions)5799 TEST_F(ValidationErrorTest, JsonNameOptionOnExtensions) {
5800 BuildFileWithErrors(
5801 "name: \"foo.proto\" "
5802 "package: \"foo\" "
5803 "message_type {"
5804 " name: \"Foo\""
5805 " extension_range { start: 10 end: 20 }"
5806 "}"
5807 "extension {"
5808 " name: \"value\""
5809 " number: 10"
5810 " label: LABEL_OPTIONAL"
5811 " type: TYPE_INT32"
5812 " extendee: \"foo.Foo\""
5813 " json_name: \"myName\""
5814 "}",
5815 "foo.proto: foo.value: OPTION_NAME: option json_name is not allowed on "
5816 "extension fields.\n");
5817 }
5818
TEST_F(ValidationErrorTest,DuplicateExtensionFieldNumber)5819 TEST_F(ValidationErrorTest, DuplicateExtensionFieldNumber) {
5820 BuildDescriptorMessagesInTestPool();
5821
5822 BuildFile(
5823 "name: \"foo.proto\" "
5824 "dependency: \"google/protobuf/descriptor.proto\" "
5825 "extension { name: \"option1\" number: 1000 label: LABEL_OPTIONAL "
5826 " type: TYPE_INT32 extendee: \"google.protobuf.FileOptions\" }");
5827
5828 BuildFileWithWarnings(
5829 "name: \"bar.proto\" "
5830 "dependency: \"google/protobuf/descriptor.proto\" "
5831 "extension { name: \"option2\" number: 1000 label: LABEL_OPTIONAL "
5832 " type: TYPE_INT32 extendee: \"google.protobuf.FileOptions\" }",
5833 "bar.proto: option2: NUMBER: Extension number 1000 has already been used "
5834 "in \"google.protobuf.FileOptions\" by extension \"option1\" defined in "
5835 "foo.proto.\n");
5836 }
5837
5838 // Helper function for tests that check for aggregate value parsing
5839 // errors. The "value" argument is embedded inside the
5840 // "uninterpreted_option" portion of the result.
EmbedAggregateValue(const char * value)5841 static std::string EmbedAggregateValue(const char* value) {
5842 return strings::Substitute(
5843 "name: \"foo.proto\" "
5844 "dependency: \"google/protobuf/descriptor.proto\" "
5845 "message_type { name: \"Foo\" } "
5846 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
5847 " type: TYPE_MESSAGE type_name: \"Foo\" "
5848 " extendee: \"google.protobuf.FileOptions\" }"
5849 "options { uninterpreted_option { name { name_part: \"foo\" "
5850 " is_extension: true } "
5851 " $0 } }",
5852 value);
5853 }
5854
TEST_F(ValidationErrorTest,AggregateValueNotFound)5855 TEST_F(ValidationErrorTest, AggregateValueNotFound) {
5856 BuildDescriptorMessagesInTestPool();
5857
5858 BuildFileWithErrors(
5859 EmbedAggregateValue("string_value: \"\""),
5860 "foo.proto: foo.proto: OPTION_VALUE: Option \"foo\" is a message. "
5861 "To set the entire message, use syntax like "
5862 "\"foo = { <proto text format> }\". To set fields within it, use "
5863 "syntax like \"foo.foo = value\".\n");
5864 }
5865
TEST_F(ValidationErrorTest,AggregateValueParseError)5866 TEST_F(ValidationErrorTest, AggregateValueParseError) {
5867 BuildDescriptorMessagesInTestPool();
5868
5869 BuildFileWithErrors(
5870 EmbedAggregateValue("aggregate_value: \"1+2\""),
5871 "foo.proto: foo.proto: OPTION_VALUE: Error while parsing option "
5872 "value for \"foo\": Expected identifier, got: 1\n");
5873 }
5874
TEST_F(ValidationErrorTest,AggregateValueUnknownFields)5875 TEST_F(ValidationErrorTest, AggregateValueUnknownFields) {
5876 BuildDescriptorMessagesInTestPool();
5877
5878 BuildFileWithErrors(
5879 EmbedAggregateValue("aggregate_value: \"x:100\""),
5880 "foo.proto: foo.proto: OPTION_VALUE: Error while parsing option "
5881 "value for \"foo\": Message type \"Foo\" has no field named \"x\".\n");
5882 }
5883
TEST_F(ValidationErrorTest,NotLiteImportsLite)5884 TEST_F(ValidationErrorTest, NotLiteImportsLite) {
5885 BuildFile(
5886 "name: \"bar.proto\" "
5887 "options { optimize_for: LITE_RUNTIME } ");
5888
5889 BuildFileWithErrors(
5890 "name: \"foo.proto\" "
5891 "dependency: \"bar.proto\" ",
5892
5893 "foo.proto: bar.proto: IMPORT: Files that do not use optimize_for = "
5894 "LITE_RUNTIME cannot import files which do use this option. This file "
5895 "is not lite, but it imports \"bar.proto\" which is.\n");
5896 }
5897
TEST_F(ValidationErrorTest,LiteExtendsNotLite)5898 TEST_F(ValidationErrorTest, LiteExtendsNotLite) {
5899 BuildFile(
5900 "name: \"bar.proto\" "
5901 "message_type: {"
5902 " name: \"Bar\""
5903 " extension_range { start: 1 end: 1000 }"
5904 "}");
5905
5906 BuildFileWithErrors(
5907 "name: \"foo.proto\" "
5908 "dependency: \"bar.proto\" "
5909 "options { optimize_for: LITE_RUNTIME } "
5910 "extension { name: \"ext\" number: 123 label: LABEL_OPTIONAL "
5911 " type: TYPE_INT32 extendee: \"Bar\" }",
5912
5913 "foo.proto: ext: EXTENDEE: Extensions to non-lite types can only be "
5914 "declared in non-lite files. Note that you cannot extend a non-lite "
5915 "type to contain a lite type, but the reverse is allowed.\n");
5916 }
5917
TEST_F(ValidationErrorTest,NoLiteServices)5918 TEST_F(ValidationErrorTest, NoLiteServices) {
5919 BuildFileWithErrors(
5920 "name: \"foo.proto\" "
5921 "options {"
5922 " optimize_for: LITE_RUNTIME"
5923 " cc_generic_services: true"
5924 " java_generic_services: true"
5925 "} "
5926 "service { name: \"Foo\" }",
5927
5928 "foo.proto: Foo: NAME: Files with optimize_for = LITE_RUNTIME cannot "
5929 "define services unless you set both options cc_generic_services and "
5930 "java_generic_services to false.\n");
5931
5932 BuildFile(
5933 "name: \"bar.proto\" "
5934 "options {"
5935 " optimize_for: LITE_RUNTIME"
5936 " cc_generic_services: false"
5937 " java_generic_services: false"
5938 "} "
5939 "service { name: \"Bar\" }");
5940 }
5941
TEST_F(ValidationErrorTest,RollbackAfterError)5942 TEST_F(ValidationErrorTest, RollbackAfterError) {
5943 // Build a file which contains every kind of construct but references an
5944 // undefined type. All these constructs will be added to the symbol table
5945 // before the undefined type error is noticed. The DescriptorPool will then
5946 // have to roll everything back.
5947 BuildFileWithErrors(
5948 "name: \"foo.proto\" "
5949 "message_type {"
5950 " name: \"TestMessage\""
5951 " field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 }"
5952 "} "
5953 "enum_type {"
5954 " name: \"TestEnum\""
5955 " value { name:\"BAR\" number:1 }"
5956 "} "
5957 "service {"
5958 " name: \"TestService\""
5959 " method {"
5960 " name: \"Baz\""
5961 " input_type: \"NoSuchType\"" // error
5962 " output_type: \"TestMessage\""
5963 " }"
5964 "}",
5965
5966 "foo.proto: TestService.Baz: INPUT_TYPE: \"NoSuchType\" is not defined.\n"
5967 );
5968
5969 // Make sure that if we build the same file again with the error fixed,
5970 // it works. If the above rollback was incomplete, then some symbols will
5971 // be left defined, and this second attempt will fail since it tries to
5972 // re-define the same symbols.
5973 BuildFile(
5974 "name: \"foo.proto\" "
5975 "message_type {"
5976 " name: \"TestMessage\""
5977 " field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 }"
5978 "} "
5979 "enum_type {"
5980 " name: \"TestEnum\""
5981 " value { name:\"BAR\" number:1 }"
5982 "} "
5983 "service {"
5984 " name: \"TestService\""
5985 " method { name:\"Baz\""
5986 " input_type:\"TestMessage\""
5987 " output_type:\"TestMessage\" }"
5988 "}");
5989 }
5990
TEST_F(ValidationErrorTest,ErrorsReportedToLogError)5991 TEST_F(ValidationErrorTest, ErrorsReportedToLogError) {
5992 // Test that errors are reported to GOOGLE_LOG(ERROR) if no error collector is
5993 // provided.
5994
5995 FileDescriptorProto file_proto;
5996 ASSERT_TRUE(
5997 TextFormat::ParseFromString("name: \"foo.proto\" "
5998 "message_type { name: \"Foo\" } "
5999 "message_type { name: \"Foo\" } ",
6000 &file_proto));
6001
6002 std::vector<std::string> errors;
6003
6004 {
6005 ScopedMemoryLog log;
6006 EXPECT_TRUE(pool_.BuildFile(file_proto) == nullptr);
6007 errors = log.GetMessages(ERROR);
6008 }
6009
6010 ASSERT_EQ(2, errors.size());
6011
6012 EXPECT_EQ("Invalid proto descriptor for file \"foo.proto\":", errors[0]);
6013 EXPECT_EQ(" Foo: \"Foo\" is already defined.", errors[1]);
6014 }
6015
TEST_F(ValidationErrorTest,DisallowEnumAlias)6016 TEST_F(ValidationErrorTest, DisallowEnumAlias) {
6017 BuildFileWithErrors(
6018 "name: \"foo.proto\" "
6019 "enum_type {"
6020 " name: \"Bar\""
6021 " value { name:\"ENUM_A\" number:0 }"
6022 " value { name:\"ENUM_B\" number:0 }"
6023 "}",
6024 "foo.proto: Bar: NUMBER: "
6025 "\"ENUM_B\" uses the same enum value as \"ENUM_A\". "
6026 "If this is intended, set 'option allow_alias = true;' to the enum "
6027 "definition.\n");
6028 }
6029
TEST_F(ValidationErrorTest,AllowEnumAlias)6030 TEST_F(ValidationErrorTest, AllowEnumAlias) {
6031 BuildFile(
6032 "name: \"foo.proto\" "
6033 "enum_type {"
6034 " name: \"Bar\""
6035 " value { name:\"ENUM_A\" number:0 }"
6036 " value { name:\"ENUM_B\" number:0 }"
6037 " options { allow_alias: true }"
6038 "}");
6039 }
6040
TEST_F(ValidationErrorTest,UnusedImportWarning)6041 TEST_F(ValidationErrorTest, UnusedImportWarning) {
6042 pool_.AddUnusedImportTrackFile("bar.proto");
6043 BuildFile(
6044 "name: \"bar.proto\" "
6045 "message_type { name: \"Bar\" }");
6046
6047 pool_.AddUnusedImportTrackFile("base.proto");
6048 BuildFile(
6049 "name: \"base.proto\" "
6050 "message_type { name: \"Base\" }");
6051
6052 pool_.AddUnusedImportTrackFile("baz.proto");
6053 BuildFile(
6054 "name: \"baz.proto\" "
6055 "message_type { name: \"Baz\" }");
6056
6057 pool_.AddUnusedImportTrackFile("public.proto");
6058 BuildFile(
6059 "name: \"public.proto\" "
6060 "dependency: \"bar.proto\""
6061 "public_dependency: 0");
6062
6063 // // forward.proto
6064 // import "base.proto" // No warning: Base message is used.
6065 // import "bar.proto" // Will log a warning.
6066 // import public "baz.proto" // No warning: Do not track import public.
6067 // import "public.proto" // No warning: public.proto has import public.
6068 // message Forward {
6069 // optional Base base = 1;
6070 // }
6071 //
6072 pool_.AddUnusedImportTrackFile("forward.proto");
6073 BuildFileWithWarnings(
6074 "name: \"forward.proto\""
6075 "dependency: \"base.proto\""
6076 "dependency: \"bar.proto\""
6077 "dependency: \"baz.proto\""
6078 "dependency: \"public.proto\""
6079 "public_dependency: 2 "
6080 "message_type {"
6081 " name: \"Forward\""
6082 " field { name:\"base\" number:1 label:LABEL_OPTIONAL "
6083 "type_name:\"Base\" }"
6084 "}",
6085 "forward.proto: bar.proto: IMPORT: Import bar.proto is unused.\n");
6086 }
6087
6088 namespace {
FillValidMapEntry(FileDescriptorProto * file_proto)6089 void FillValidMapEntry(FileDescriptorProto* file_proto) {
6090 ASSERT_TRUE(TextFormat::ParseFromString(
6091 "name: 'foo.proto' "
6092 "message_type { "
6093 " name: 'Foo' "
6094 " field { "
6095 " name: 'foo_map' number: 1 label:LABEL_REPEATED "
6096 " type_name: 'FooMapEntry' "
6097 " } "
6098 " nested_type { "
6099 " name: 'FooMapEntry' "
6100 " options { map_entry: true } "
6101 " field { "
6102 " name: 'key' number: 1 type:TYPE_INT32 label:LABEL_OPTIONAL "
6103 " } "
6104 " field { "
6105 " name: 'value' number: 2 type:TYPE_INT32 label:LABEL_OPTIONAL "
6106 " } "
6107 " } "
6108 "} "
6109 "message_type { "
6110 " name: 'Bar' "
6111 " extension_range { start: 1 end: 10 }"
6112 "} ",
6113 file_proto));
6114 }
6115 static const char* kMapEntryErrorMessage =
6116 "foo.proto: Foo.foo_map: TYPE: map_entry should not be set explicitly. "
6117 "Use map<KeyType, ValueType> instead.\n";
6118 static const char* kMapEntryKeyTypeErrorMessage =
6119 "foo.proto: Foo.foo_map: TYPE: Key in map fields cannot be float/double, "
6120 "bytes or message types.\n";
6121
6122 } // namespace
6123
TEST_F(ValidationErrorTest,MapEntryBase)6124 TEST_F(ValidationErrorTest, MapEntryBase) {
6125 FileDescriptorProto file_proto;
6126 FillValidMapEntry(&file_proto);
6127 BuildFile(file_proto.DebugString());
6128 }
6129
TEST_F(ValidationErrorTest,MapEntryExtensionRange)6130 TEST_F(ValidationErrorTest, MapEntryExtensionRange) {
6131 FileDescriptorProto file_proto;
6132 FillValidMapEntry(&file_proto);
6133 TextFormat::MergeFromString(
6134 "extension_range { "
6135 " start: 10 end: 20 "
6136 "} ",
6137 file_proto.mutable_message_type(0)->mutable_nested_type(0));
6138 BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
6139 }
6140
TEST_F(ValidationErrorTest,MapEntryExtension)6141 TEST_F(ValidationErrorTest, MapEntryExtension) {
6142 FileDescriptorProto file_proto;
6143 FillValidMapEntry(&file_proto);
6144 TextFormat::MergeFromString(
6145 "extension { "
6146 " name: 'foo_ext' extendee: '.Bar' number: 5"
6147 "} ",
6148 file_proto.mutable_message_type(0)->mutable_nested_type(0));
6149 BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
6150 }
6151
TEST_F(ValidationErrorTest,MapEntryNestedType)6152 TEST_F(ValidationErrorTest, MapEntryNestedType) {
6153 FileDescriptorProto file_proto;
6154 FillValidMapEntry(&file_proto);
6155 TextFormat::MergeFromString(
6156 "nested_type { "
6157 " name: 'Bar' "
6158 "} ",
6159 file_proto.mutable_message_type(0)->mutable_nested_type(0));
6160 BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
6161 }
6162
TEST_F(ValidationErrorTest,MapEntryEnumTypes)6163 TEST_F(ValidationErrorTest, MapEntryEnumTypes) {
6164 FileDescriptorProto file_proto;
6165 FillValidMapEntry(&file_proto);
6166 TextFormat::MergeFromString(
6167 "enum_type { "
6168 " name: 'BarEnum' "
6169 " value { name: 'BAR_BAR' number:0 } "
6170 "} ",
6171 file_proto.mutable_message_type(0)->mutable_nested_type(0));
6172 BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
6173 }
6174
TEST_F(ValidationErrorTest,MapEntryExtraField)6175 TEST_F(ValidationErrorTest, MapEntryExtraField) {
6176 FileDescriptorProto file_proto;
6177 FillValidMapEntry(&file_proto);
6178 TextFormat::MergeFromString(
6179 "field { "
6180 " name: 'other_field' "
6181 " label: LABEL_OPTIONAL "
6182 " type: TYPE_INT32 "
6183 " number: 3 "
6184 "} ",
6185 file_proto.mutable_message_type(0)->mutable_nested_type(0));
6186 BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
6187 }
6188
TEST_F(ValidationErrorTest,MapEntryMessageName)6189 TEST_F(ValidationErrorTest, MapEntryMessageName) {
6190 FileDescriptorProto file_proto;
6191 FillValidMapEntry(&file_proto);
6192 file_proto.mutable_message_type(0)->mutable_nested_type(0)->set_name(
6193 "OtherMapEntry");
6194 file_proto.mutable_message_type(0)->mutable_field(0)->set_type_name(
6195 "OtherMapEntry");
6196 BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
6197 }
6198
TEST_F(ValidationErrorTest,MapEntryNoneRepeatedMapEntry)6199 TEST_F(ValidationErrorTest, MapEntryNoneRepeatedMapEntry) {
6200 FileDescriptorProto file_proto;
6201 FillValidMapEntry(&file_proto);
6202 file_proto.mutable_message_type(0)->mutable_field(0)->set_label(
6203 FieldDescriptorProto::LABEL_OPTIONAL);
6204 BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
6205 }
6206
TEST_F(ValidationErrorTest,MapEntryDifferentContainingType)6207 TEST_F(ValidationErrorTest, MapEntryDifferentContainingType) {
6208 FileDescriptorProto file_proto;
6209 FillValidMapEntry(&file_proto);
6210 // Move the nested MapEntry message into the top level, which should not pass
6211 // the validation.
6212 file_proto.mutable_message_type()->AddAllocated(
6213 file_proto.mutable_message_type(0)->mutable_nested_type()->ReleaseLast());
6214 BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
6215 }
6216
TEST_F(ValidationErrorTest,MapEntryKeyName)6217 TEST_F(ValidationErrorTest, MapEntryKeyName) {
6218 FileDescriptorProto file_proto;
6219 FillValidMapEntry(&file_proto);
6220 FieldDescriptorProto* key =
6221 file_proto.mutable_message_type(0)->mutable_nested_type(0)->mutable_field(
6222 0);
6223 key->set_name("Key");
6224 BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
6225 }
6226
TEST_F(ValidationErrorTest,MapEntryKeyLabel)6227 TEST_F(ValidationErrorTest, MapEntryKeyLabel) {
6228 FileDescriptorProto file_proto;
6229 FillValidMapEntry(&file_proto);
6230 FieldDescriptorProto* key =
6231 file_proto.mutable_message_type(0)->mutable_nested_type(0)->mutable_field(
6232 0);
6233 key->set_label(FieldDescriptorProto::LABEL_REQUIRED);
6234 BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
6235 }
6236
TEST_F(ValidationErrorTest,MapEntryKeyNumber)6237 TEST_F(ValidationErrorTest, MapEntryKeyNumber) {
6238 FileDescriptorProto file_proto;
6239 FillValidMapEntry(&file_proto);
6240 FieldDescriptorProto* key =
6241 file_proto.mutable_message_type(0)->mutable_nested_type(0)->mutable_field(
6242 0);
6243 key->set_number(3);
6244 BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
6245 }
6246
TEST_F(ValidationErrorTest,MapEntryValueName)6247 TEST_F(ValidationErrorTest, MapEntryValueName) {
6248 FileDescriptorProto file_proto;
6249 FillValidMapEntry(&file_proto);
6250 FieldDescriptorProto* value =
6251 file_proto.mutable_message_type(0)->mutable_nested_type(0)->mutable_field(
6252 1);
6253 value->set_name("Value");
6254 BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
6255 }
6256
TEST_F(ValidationErrorTest,MapEntryValueLabel)6257 TEST_F(ValidationErrorTest, MapEntryValueLabel) {
6258 FileDescriptorProto file_proto;
6259 FillValidMapEntry(&file_proto);
6260 FieldDescriptorProto* value =
6261 file_proto.mutable_message_type(0)->mutable_nested_type(0)->mutable_field(
6262 1);
6263 value->set_label(FieldDescriptorProto::LABEL_REQUIRED);
6264 BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
6265 }
6266
TEST_F(ValidationErrorTest,MapEntryValueNumber)6267 TEST_F(ValidationErrorTest, MapEntryValueNumber) {
6268 FileDescriptorProto file_proto;
6269 FillValidMapEntry(&file_proto);
6270 FieldDescriptorProto* value =
6271 file_proto.mutable_message_type(0)->mutable_nested_type(0)->mutable_field(
6272 1);
6273 value->set_number(3);
6274 BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
6275 }
6276
TEST_F(ValidationErrorTest,MapEntryKeyTypeFloat)6277 TEST_F(ValidationErrorTest, MapEntryKeyTypeFloat) {
6278 FileDescriptorProto file_proto;
6279 FillValidMapEntry(&file_proto);
6280 FieldDescriptorProto* key =
6281 file_proto.mutable_message_type(0)->mutable_nested_type(0)->mutable_field(
6282 0);
6283 key->set_type(FieldDescriptorProto::TYPE_FLOAT);
6284 BuildFileWithErrors(file_proto.DebugString(), kMapEntryKeyTypeErrorMessage);
6285 }
6286
TEST_F(ValidationErrorTest,MapEntryKeyTypeDouble)6287 TEST_F(ValidationErrorTest, MapEntryKeyTypeDouble) {
6288 FileDescriptorProto file_proto;
6289 FillValidMapEntry(&file_proto);
6290 FieldDescriptorProto* key =
6291 file_proto.mutable_message_type(0)->mutable_nested_type(0)->mutable_field(
6292 0);
6293 key->set_type(FieldDescriptorProto::TYPE_DOUBLE);
6294 BuildFileWithErrors(file_proto.DebugString(), kMapEntryKeyTypeErrorMessage);
6295 }
6296
TEST_F(ValidationErrorTest,MapEntryKeyTypeBytes)6297 TEST_F(ValidationErrorTest, MapEntryKeyTypeBytes) {
6298 FileDescriptorProto file_proto;
6299 FillValidMapEntry(&file_proto);
6300 FieldDescriptorProto* key =
6301 file_proto.mutable_message_type(0)->mutable_nested_type(0)->mutable_field(
6302 0);
6303 key->set_type(FieldDescriptorProto::TYPE_BYTES);
6304 BuildFileWithErrors(file_proto.DebugString(), kMapEntryKeyTypeErrorMessage);
6305 }
6306
TEST_F(ValidationErrorTest,MapEntryKeyTypeEnum)6307 TEST_F(ValidationErrorTest, MapEntryKeyTypeEnum) {
6308 FileDescriptorProto file_proto;
6309 FillValidMapEntry(&file_proto);
6310 FieldDescriptorProto* key =
6311 file_proto.mutable_message_type(0)->mutable_nested_type(0)->mutable_field(
6312 0);
6313 key->clear_type();
6314 key->set_type_name("BarEnum");
6315 EnumDescriptorProto* enum_proto = file_proto.add_enum_type();
6316 enum_proto->set_name("BarEnum");
6317 EnumValueDescriptorProto* enum_value_proto = enum_proto->add_value();
6318 enum_value_proto->set_name("BAR_VALUE0");
6319 enum_value_proto->set_number(0);
6320 BuildFileWithErrors(file_proto.DebugString(),
6321 "foo.proto: Foo.foo_map: TYPE: Key in map fields cannot "
6322 "be enum types.\n");
6323 // Enum keys are not allowed in proto3 as well.
6324 // Get rid of extensions for proto3 to make it proto3 compatible.
6325 file_proto.mutable_message_type()->RemoveLast();
6326 file_proto.set_syntax("proto3");
6327 BuildFileWithErrors(file_proto.DebugString(),
6328 "foo.proto: Foo.foo_map: TYPE: Key in map fields cannot "
6329 "be enum types.\n");
6330 }
6331
TEST_F(ValidationErrorTest,MapEntryKeyTypeMessage)6332 TEST_F(ValidationErrorTest, MapEntryKeyTypeMessage) {
6333 FileDescriptorProto file_proto;
6334 FillValidMapEntry(&file_proto);
6335 FieldDescriptorProto* key =
6336 file_proto.mutable_message_type(0)->mutable_nested_type(0)->mutable_field(
6337 0);
6338 key->clear_type();
6339 key->set_type_name(".Bar");
6340 BuildFileWithErrors(file_proto.DebugString(), kMapEntryKeyTypeErrorMessage);
6341 }
6342
TEST_F(ValidationErrorTest,MapEntryConflictsWithField)6343 TEST_F(ValidationErrorTest, MapEntryConflictsWithField) {
6344 FileDescriptorProto file_proto;
6345 FillValidMapEntry(&file_proto);
6346 TextFormat::MergeFromString(
6347 "field { "
6348 " name: 'FooMapEntry' "
6349 " type: TYPE_INT32 "
6350 " label: LABEL_OPTIONAL "
6351 " number: 100 "
6352 "}",
6353 file_proto.mutable_message_type(0));
6354 BuildFileWithErrors(
6355 file_proto.DebugString(),
6356 "foo.proto: Foo.FooMapEntry: NAME: \"FooMapEntry\" is already defined in "
6357 "\"Foo\".\n"
6358 "foo.proto: Foo.foo_map: TYPE: \"FooMapEntry\" is not defined.\n"
6359 "foo.proto: Foo: NAME: Expanded map entry type FooMapEntry conflicts "
6360 "with an existing field.\n");
6361 }
6362
TEST_F(ValidationErrorTest,MapEntryConflictsWithMessage)6363 TEST_F(ValidationErrorTest, MapEntryConflictsWithMessage) {
6364 FileDescriptorProto file_proto;
6365 FillValidMapEntry(&file_proto);
6366 TextFormat::MergeFromString(
6367 "nested_type { "
6368 " name: 'FooMapEntry' "
6369 "}",
6370 file_proto.mutable_message_type(0));
6371 BuildFileWithErrors(
6372 file_proto.DebugString(),
6373 "foo.proto: Foo.FooMapEntry: NAME: \"FooMapEntry\" is already defined in "
6374 "\"Foo\".\n"
6375 "foo.proto: Foo: NAME: Expanded map entry type FooMapEntry conflicts "
6376 "with an existing nested message type.\n");
6377 }
6378
TEST_F(ValidationErrorTest,MapEntryConflictsWithEnum)6379 TEST_F(ValidationErrorTest, MapEntryConflictsWithEnum) {
6380 FileDescriptorProto file_proto;
6381 FillValidMapEntry(&file_proto);
6382 TextFormat::MergeFromString(
6383 "enum_type { "
6384 " name: 'FooMapEntry' "
6385 " value { name: 'ENTRY_FOO' number: 0 }"
6386 "}",
6387 file_proto.mutable_message_type(0));
6388 BuildFileWithErrors(
6389 file_proto.DebugString(),
6390 "foo.proto: Foo.FooMapEntry: NAME: \"FooMapEntry\" is already defined in "
6391 "\"Foo\".\n"
6392 "foo.proto: Foo: NAME: Expanded map entry type FooMapEntry conflicts "
6393 "with an existing enum type.\n");
6394 }
6395
TEST_F(ValidationErrorTest,EnumValuesConflictWithDifferentCasing)6396 TEST_F(ValidationErrorTest, EnumValuesConflictWithDifferentCasing) {
6397 BuildFileWithErrors(
6398 "syntax: 'proto3'"
6399 "name: 'foo.proto' "
6400 "enum_type {"
6401 " name: 'FooEnum' "
6402 " value { name: 'BAR' number: 0 }"
6403 " value { name: 'bar' number: 1 }"
6404 "}",
6405 "foo.proto: bar: NAME: Enum name bar has the same name as BAR "
6406 "if you ignore case and strip out the enum name prefix (if any). "
6407 "This is error-prone and can lead to undefined behavior. "
6408 "Please avoid doing this. If you are using allow_alias, please assign "
6409 "the same numeric value to both enums.\n");
6410
6411 // Not an error because both enums are mapped to the same value.
6412 BuildFile(
6413 "syntax: 'proto3'"
6414 "name: 'foo.proto' "
6415 "enum_type {"
6416 " name: 'FooEnum' "
6417 " options { allow_alias: true }"
6418 " value { name: 'UNKNOWN' number: 0 }"
6419 " value { name: 'BAR' number: 1 }"
6420 " value { name: 'bar' number: 1 }"
6421 "}");
6422 }
6423
TEST_F(ValidationErrorTest,EnumValuesConflictWhenPrefixesStripped)6424 TEST_F(ValidationErrorTest, EnumValuesConflictWhenPrefixesStripped) {
6425 BuildFileWithErrors(
6426 "syntax: 'proto3'"
6427 "name: 'foo.proto' "
6428 "enum_type {"
6429 " name: 'FooEnum' "
6430 " value { name: 'FOO_ENUM_BAZ' number: 0 }"
6431 " value { name: 'BAZ' number: 1 }"
6432 "}",
6433 "foo.proto: BAZ: NAME: Enum name BAZ has the same name as FOO_ENUM_BAZ "
6434 "if you ignore case and strip out the enum name prefix (if any). "
6435 "This is error-prone and can lead to undefined behavior. "
6436 "Please avoid doing this. If you are using allow_alias, please assign "
6437 "the same numeric value to both enums.\n");
6438
6439 BuildFileWithErrors(
6440 "syntax: 'proto3'"
6441 "name: 'foo.proto' "
6442 "enum_type {"
6443 " name: 'FooEnum' "
6444 " value { name: 'FOOENUM_BAZ' number: 0 }"
6445 " value { name: 'BAZ' number: 1 }"
6446 "}",
6447 "foo.proto: BAZ: NAME: Enum name BAZ has the same name as FOOENUM_BAZ "
6448 "if you ignore case and strip out the enum name prefix (if any). "
6449 "This is error-prone and can lead to undefined behavior. "
6450 "Please avoid doing this. If you are using allow_alias, please assign "
6451 "the same numeric value to both enums.\n");
6452
6453 BuildFileWithErrors(
6454 "syntax: 'proto3'"
6455 "name: 'foo.proto' "
6456 "enum_type {"
6457 " name: 'FooEnum' "
6458 " value { name: 'FOO_ENUM_BAR_BAZ' number: 0 }"
6459 " value { name: 'BAR__BAZ' number: 1 }"
6460 "}",
6461 "foo.proto: BAR__BAZ: NAME: Enum name BAR__BAZ has the same name as "
6462 "FOO_ENUM_BAR_BAZ if you ignore case and strip out the enum name prefix "
6463 "(if any). This is error-prone and can lead to undefined behavior. "
6464 "Please avoid doing this. If you are using allow_alias, please assign "
6465 "the same numeric value to both enums.\n");
6466
6467 BuildFileWithErrors(
6468 "syntax: 'proto3'"
6469 "name: 'foo.proto' "
6470 "enum_type {"
6471 " name: 'FooEnum' "
6472 " value { name: 'FOO_ENUM__BAR_BAZ' number: 0 }"
6473 " value { name: 'BAR_BAZ' number: 1 }"
6474 "}",
6475 "foo.proto: BAR_BAZ: NAME: Enum name BAR_BAZ has the same name as "
6476 "FOO_ENUM__BAR_BAZ if you ignore case and strip out the enum name prefix "
6477 "(if any). This is error-prone and can lead to undefined behavior. "
6478 "Please avoid doing this. If you are using allow_alias, please assign "
6479 "the same numeric value to both enums.\n");
6480
6481 // This isn't an error because the underscore will cause the PascalCase to
6482 // differ by case (BarBaz vs. Barbaz).
6483 BuildFile(
6484 "syntax: 'proto3'"
6485 "name: 'foo.proto' "
6486 "enum_type {"
6487 " name: 'FooEnum' "
6488 " value { name: 'BAR_BAZ' number: 0 }"
6489 " value { name: 'BARBAZ' number: 1 }"
6490 "}");
6491 }
6492
TEST_F(ValidationErrorTest,MapEntryConflictsWithOneof)6493 TEST_F(ValidationErrorTest, MapEntryConflictsWithOneof) {
6494 FileDescriptorProto file_proto;
6495 FillValidMapEntry(&file_proto);
6496 TextFormat::MergeFromString(
6497 "oneof_decl { "
6498 " name: 'FooMapEntry' "
6499 "}"
6500 "field { "
6501 " name: 'int_field' "
6502 " type: TYPE_INT32 "
6503 " label: LABEL_OPTIONAL "
6504 " oneof_index: 0 "
6505 " number: 100 "
6506 "} ",
6507 file_proto.mutable_message_type(0));
6508 BuildFileWithErrors(
6509 file_proto.DebugString(),
6510 "foo.proto: Foo.FooMapEntry: NAME: \"FooMapEntry\" is already defined in "
6511 "\"Foo\".\n"
6512 "foo.proto: Foo.foo_map: TYPE: \"FooMapEntry\" is not defined.\n"
6513 "foo.proto: Foo: NAME: Expanded map entry type FooMapEntry conflicts "
6514 "with an existing oneof type.\n");
6515 }
6516
TEST_F(ValidationErrorTest,MapEntryUsesNoneZeroEnumDefaultValue)6517 TEST_F(ValidationErrorTest, MapEntryUsesNoneZeroEnumDefaultValue) {
6518 BuildFileWithErrors(
6519 "name: \"foo.proto\" "
6520 "enum_type {"
6521 " name: \"Bar\""
6522 " value { name:\"ENUM_A\" number:1 }"
6523 " value { name:\"ENUM_B\" number:2 }"
6524 "}"
6525 "message_type {"
6526 " name: 'Foo' "
6527 " field { "
6528 " name: 'foo_map' number: 1 label:LABEL_REPEATED "
6529 " type_name: 'FooMapEntry' "
6530 " } "
6531 " nested_type { "
6532 " name: 'FooMapEntry' "
6533 " options { map_entry: true } "
6534 " field { "
6535 " name: 'key' number: 1 type:TYPE_INT32 label:LABEL_OPTIONAL "
6536 " } "
6537 " field { "
6538 " name: 'value' number: 2 type_name:\"Bar\" label:LABEL_OPTIONAL "
6539 " } "
6540 " } "
6541 "}",
6542 "foo.proto: Foo.foo_map: "
6543 "TYPE: Enum value in map must define 0 as the first value.\n");
6544 }
6545
TEST_F(ValidationErrorTest,Proto3RequiredFields)6546 TEST_F(ValidationErrorTest, Proto3RequiredFields) {
6547 BuildFileWithErrors(
6548 "name: 'foo.proto' "
6549 "syntax: 'proto3' "
6550 "message_type { "
6551 " name: 'Foo' "
6552 " field { name:'foo' number:1 label:LABEL_REQUIRED type:TYPE_INT32 } "
6553 "}",
6554 "foo.proto: Foo.foo: TYPE: Required fields are not allowed in "
6555 "proto3.\n");
6556
6557 // applied to nested types as well.
6558 BuildFileWithErrors(
6559 "name: 'foo.proto' "
6560 "syntax: 'proto3' "
6561 "message_type { "
6562 " name: 'Foo' "
6563 " nested_type { "
6564 " name : 'Bar' "
6565 " field { name:'bar' number:1 label:LABEL_REQUIRED type:TYPE_INT32 } "
6566 " } "
6567 "}",
6568 "foo.proto: Foo.Bar.bar: TYPE: Required fields are not allowed in "
6569 "proto3.\n");
6570
6571 // optional and repeated fields are OK.
6572 BuildFile(
6573 "name: 'foo.proto' "
6574 "syntax: 'proto3' "
6575 "message_type { "
6576 " name: 'Foo' "
6577 " field { name:'foo' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 } "
6578 " field { name:'bar' number:2 label:LABEL_REPEATED type:TYPE_INT32 } "
6579 "}");
6580 }
6581
TEST_F(ValidationErrorTest,ValidateProto3DefaultValue)6582 TEST_F(ValidationErrorTest, ValidateProto3DefaultValue) {
6583 BuildFileWithErrors(
6584 "name: 'foo.proto' "
6585 "syntax: 'proto3' "
6586 "message_type { "
6587 " name: 'Foo' "
6588 " field { name:'foo' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 "
6589 " default_value: '1' }"
6590 "}",
6591 "foo.proto: Foo.foo: DEFAULT_VALUE: Explicit default values are not "
6592 "allowed in proto3.\n");
6593
6594 BuildFileWithErrors(
6595 "name: 'foo.proto' "
6596 "syntax: 'proto3' "
6597 "message_type { "
6598 " name: 'Foo' "
6599 " nested_type { "
6600 " name : 'Bar' "
6601 " field { name:'bar' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 "
6602 " default_value: '1' }"
6603 " } "
6604 "}",
6605 "foo.proto: Foo.Bar.bar: DEFAULT_VALUE: Explicit default values are not "
6606 "allowed in proto3.\n");
6607 }
6608
TEST_F(ValidationErrorTest,ValidateProto3ExtensionRange)6609 TEST_F(ValidationErrorTest, ValidateProto3ExtensionRange) {
6610 BuildFileWithErrors(
6611 "name: 'foo.proto' "
6612 "syntax: 'proto3' "
6613 "message_type { "
6614 " name: 'Foo' "
6615 " field { name:'foo' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 } "
6616 " extension_range { start:10 end:100 } "
6617 "}",
6618 "foo.proto: Foo: NUMBER: Extension ranges are not allowed in "
6619 "proto3.\n");
6620
6621 BuildFileWithErrors(
6622 "name: 'foo.proto' "
6623 "syntax: 'proto3' "
6624 "message_type { "
6625 " name: 'Foo' "
6626 " nested_type { "
6627 " name : 'Bar' "
6628 " field { name:'bar' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 } "
6629 " extension_range { start:10 end:100 } "
6630 " } "
6631 "}",
6632 "foo.proto: Foo.Bar: NUMBER: Extension ranges are not allowed in "
6633 "proto3.\n");
6634 }
6635
TEST_F(ValidationErrorTest,ValidateProto3MessageSetWireFormat)6636 TEST_F(ValidationErrorTest, ValidateProto3MessageSetWireFormat) {
6637 BuildFileWithErrors(
6638 "name: 'foo.proto' "
6639 "syntax: 'proto3' "
6640 "message_type { "
6641 " name: 'Foo' "
6642 " options { message_set_wire_format: true } "
6643 "}",
6644 "foo.proto: Foo: NAME: MessageSet is not supported "
6645 "in proto3.\n");
6646 }
6647
TEST_F(ValidationErrorTest,ValidateProto3Enum)6648 TEST_F(ValidationErrorTest, ValidateProto3Enum) {
6649 BuildFileWithErrors(
6650 "name: 'foo.proto' "
6651 "syntax: 'proto3' "
6652 "enum_type { "
6653 " name: 'FooEnum' "
6654 " value { name: 'FOO_FOO' number:1 } "
6655 "}",
6656 "foo.proto: FooEnum: NUMBER: The first enum value must be "
6657 "zero in proto3.\n");
6658
6659 BuildFileWithErrors(
6660 "name: 'foo.proto' "
6661 "syntax: 'proto3' "
6662 "message_type { "
6663 " name: 'Foo' "
6664 " enum_type { "
6665 " name: 'FooEnum' "
6666 " value { name: 'FOO_FOO' number:1 } "
6667 " } "
6668 "}",
6669 "foo.proto: Foo.FooEnum: NUMBER: The first enum value must be "
6670 "zero in proto3.\n");
6671
6672 // valid case.
6673 BuildFile(
6674 "name: 'foo.proto' "
6675 "syntax: 'proto3' "
6676 "enum_type { "
6677 " name: 'FooEnum' "
6678 " value { name: 'FOO_FOO' number:0 } "
6679 "}");
6680 }
6681
TEST_F(ValidationErrorTest,ValidateProto3Group)6682 TEST_F(ValidationErrorTest, ValidateProto3Group) {
6683 BuildFileWithErrors(
6684 "name: 'foo.proto' "
6685 "syntax: 'proto3' "
6686 "message_type { "
6687 " name: 'Foo' "
6688 " nested_type { "
6689 " name: 'FooGroup' "
6690 " } "
6691 " field { name:'foo_group' number: 1 label:LABEL_OPTIONAL "
6692 " type: TYPE_GROUP type_name:'FooGroup' } "
6693 "}",
6694 "foo.proto: Foo.foo_group: TYPE: Groups are not supported in proto3 "
6695 "syntax.\n");
6696 }
6697
6698
TEST_F(ValidationErrorTest,ValidateProto3EnumFromProto2)6699 TEST_F(ValidationErrorTest, ValidateProto3EnumFromProto2) {
6700 // Define an enum in a proto2 file.
6701 BuildFile(
6702 "name: 'foo.proto' "
6703 "package: 'foo' "
6704 "syntax: 'proto2' "
6705 "enum_type { "
6706 " name: 'FooEnum' "
6707 " value { name: 'DEFAULT_OPTION' number:0 } "
6708 "}");
6709
6710 // Now try to refer to it. (All tests in the fixture use the same pool, so we
6711 // can refer to the enum above in this definition.)
6712 BuildFileWithErrors(
6713 "name: 'bar.proto' "
6714 "dependency: 'foo.proto' "
6715 "syntax: 'proto3' "
6716 "message_type { "
6717 " name: 'Foo' "
6718 " field { name:'bar' number:1 label:LABEL_OPTIONAL type:TYPE_ENUM "
6719 " type_name: 'foo.FooEnum' }"
6720 "}",
6721 "bar.proto: Foo.bar: TYPE: Enum type \"foo.FooEnum\" is not a proto3 "
6722 "enum, but is used in \"Foo\" which is a proto3 message type.\n");
6723 }
6724
TEST_F(ValidationErrorTest,ValidateProto3Extension)6725 TEST_F(ValidationErrorTest, ValidateProto3Extension) {
6726 // Valid for options.
6727 DescriptorPool pool;
6728 FileDescriptorProto file_proto;
6729 // Add "google/protobuf/descriptor.proto".
6730 FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto);
6731 ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
6732 // Add "foo.proto":
6733 // import "google/protobuf/descriptor.proto";
6734 // extend google.protobuf.FieldOptions {
6735 // optional int32 option1 = 1000;
6736 // }
6737 file_proto.Clear();
6738 file_proto.set_name("foo.proto");
6739 file_proto.set_syntax("proto3");
6740 file_proto.add_dependency("google/protobuf/descriptor.proto");
6741 AddExtension(&file_proto, "google.protobuf.FieldOptions", "option1", 1000,
6742 FieldDescriptorProto::LABEL_OPTIONAL,
6743 FieldDescriptorProto::TYPE_INT32);
6744 ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
6745
6746 // Copy and change the package of the descriptor.proto
6747 BuildFile(
6748 "name: 'google.protobuf.proto' "
6749 "syntax: 'proto2' "
6750 "message_type { "
6751 " name: 'Container' extension_range { start: 1 end: 1000 } "
6752 "}");
6753 BuildFileWithErrors(
6754 "name: 'bar.proto' "
6755 "syntax: 'proto3' "
6756 "dependency: 'google.protobuf.proto' "
6757 "extension { "
6758 " name: 'bar' number: 1 label: LABEL_OPTIONAL type: TYPE_INT32 "
6759 " extendee: 'Container' "
6760 "}",
6761 "bar.proto: bar: EXTENDEE: Extensions in proto3 are only allowed for "
6762 "defining options.\n");
6763 }
6764
6765 // Test that field names that may conflict in JSON is not allowed by protoc.
TEST_F(ValidationErrorTest,ValidateProto3JsonName)6766 TEST_F(ValidationErrorTest, ValidateProto3JsonName) {
6767 // The comparison is case-insensitive.
6768 BuildFileWithErrors(
6769 "name: 'foo.proto' "
6770 "syntax: 'proto3' "
6771 "message_type {"
6772 " name: 'Foo'"
6773 " field { name:'name' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 }"
6774 " field { name:'Name' number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }"
6775 "}",
6776 "foo.proto: Foo: NAME: The JSON camel-case name of field \"Name\" "
6777 "conflicts with field \"name\". This is not allowed in proto3.\n");
6778 // Underscores are ignored.
6779 BuildFileWithErrors(
6780 "name: 'foo.proto' "
6781 "syntax: 'proto3' "
6782 "message_type {"
6783 " name: 'Foo'"
6784 " field { name:'ab' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 }"
6785 " field { name:'_a__b_' number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }"
6786 "}",
6787 "foo.proto: Foo: NAME: The JSON camel-case name of field \"_a__b_\" "
6788 "conflicts with field \"ab\". This is not allowed in proto3.\n");
6789 }
6790
6791
TEST_F(ValidationErrorTest,UnusedImportWithOtherError)6792 TEST_F(ValidationErrorTest, UnusedImportWithOtherError) {
6793 BuildFile(
6794 "name: 'bar.proto' "
6795 "message_type {"
6796 " name: 'Bar'"
6797 "}");
6798
6799 pool_.AddUnusedImportTrackFile("foo.proto", true);
6800 BuildFileWithErrors(
6801 "name: 'foo.proto' "
6802 "dependency: 'bar.proto' "
6803 "message_type {"
6804 " name: 'Foo'"
6805 " extension { name:'foo' number:1 label:LABEL_OPTIONAL type:TYPE_INT32"
6806 " extendee: 'Baz' }"
6807 "}",
6808
6809 // Should not also contain unused import error.
6810 "foo.proto: Foo.foo: EXTENDEE: \"Baz\" is not defined.\n");
6811 }
6812
6813
6814 // ===================================================================
6815 // DescriptorDatabase
6816
AddToDatabase(SimpleDescriptorDatabase * database,const char * file_text)6817 static void AddToDatabase(SimpleDescriptorDatabase* database,
6818 const char* file_text) {
6819 FileDescriptorProto file_proto;
6820 EXPECT_TRUE(TextFormat::ParseFromString(file_text, &file_proto));
6821 database->Add(file_proto);
6822 }
6823
6824 class DatabaseBackedPoolTest : public testing::Test {
6825 protected:
DatabaseBackedPoolTest()6826 DatabaseBackedPoolTest() {}
6827
6828 SimpleDescriptorDatabase database_;
6829
SetUp()6830 void SetUp() override {
6831 AddToDatabase(
6832 &database_,
6833 "name: 'foo.proto' "
6834 "message_type { name:'Foo' extension_range { start: 1 end: 100 } } "
6835 "enum_type { name:'TestEnum' value { name:'DUMMY' number:0 } } "
6836 "service { name:'TestService' } ");
6837 AddToDatabase(&database_,
6838 "name: 'bar.proto' "
6839 "dependency: 'foo.proto' "
6840 "message_type { name:'Bar' } "
6841 "extension { name:'foo_ext' extendee: '.Foo' number:5 "
6842 " label:LABEL_OPTIONAL type:TYPE_INT32 } ");
6843 // Baz has an undeclared dependency on Foo.
6844 AddToDatabase(
6845 &database_,
6846 "name: 'baz.proto' "
6847 "message_type { "
6848 " name:'Baz' "
6849 " field { name:'foo' number:1 label:LABEL_OPTIONAL type_name:'Foo' } "
6850 "}");
6851 }
6852
6853 // We can't inject a file containing errors into a DescriptorPool, so we
6854 // need an actual mock DescriptorDatabase to test errors.
6855 class ErrorDescriptorDatabase : public DescriptorDatabase {
6856 public:
ErrorDescriptorDatabase()6857 ErrorDescriptorDatabase() {}
~ErrorDescriptorDatabase()6858 ~ErrorDescriptorDatabase() override {}
6859
6860 // implements DescriptorDatabase ---------------------------------
FindFileByName(const std::string & filename,FileDescriptorProto * output)6861 bool FindFileByName(const std::string& filename,
6862 FileDescriptorProto* output) override {
6863 // error.proto and error2.proto cyclically import each other.
6864 if (filename == "error.proto") {
6865 output->Clear();
6866 output->set_name("error.proto");
6867 output->add_dependency("error2.proto");
6868 return true;
6869 } else if (filename == "error2.proto") {
6870 output->Clear();
6871 output->set_name("error2.proto");
6872 output->add_dependency("error.proto");
6873 return true;
6874 } else {
6875 return false;
6876 }
6877 }
FindFileContainingSymbol(const std::string & symbol_name,FileDescriptorProto * output)6878 bool FindFileContainingSymbol(const std::string& symbol_name,
6879 FileDescriptorProto* output) override {
6880 return false;
6881 }
FindFileContainingExtension(const std::string & containing_type,int field_number,FileDescriptorProto * output)6882 bool FindFileContainingExtension(const std::string& containing_type,
6883 int field_number,
6884 FileDescriptorProto* output) override {
6885 return false;
6886 }
6887 };
6888
6889 // A DescriptorDatabase that counts how many times each method has been
6890 // called and forwards to some other DescriptorDatabase.
6891 class CallCountingDatabase : public DescriptorDatabase {
6892 public:
CallCountingDatabase(DescriptorDatabase * wrapped_db)6893 CallCountingDatabase(DescriptorDatabase* wrapped_db)
6894 : wrapped_db_(wrapped_db) {
6895 Clear();
6896 }
~CallCountingDatabase()6897 ~CallCountingDatabase() override {}
6898
6899 DescriptorDatabase* wrapped_db_;
6900
6901 int call_count_;
6902
Clear()6903 void Clear() { call_count_ = 0; }
6904
6905 // implements DescriptorDatabase ---------------------------------
FindFileByName(const std::string & filename,FileDescriptorProto * output)6906 bool FindFileByName(const std::string& filename,
6907 FileDescriptorProto* output) override {
6908 ++call_count_;
6909 return wrapped_db_->FindFileByName(filename, output);
6910 }
FindFileContainingSymbol(const std::string & symbol_name,FileDescriptorProto * output)6911 bool FindFileContainingSymbol(const std::string& symbol_name,
6912 FileDescriptorProto* output) override {
6913 ++call_count_;
6914 return wrapped_db_->FindFileContainingSymbol(symbol_name, output);
6915 }
FindFileContainingExtension(const std::string & containing_type,int field_number,FileDescriptorProto * output)6916 bool FindFileContainingExtension(const std::string& containing_type,
6917 int field_number,
6918 FileDescriptorProto* output) override {
6919 ++call_count_;
6920 return wrapped_db_->FindFileContainingExtension(containing_type,
6921 field_number, output);
6922 }
6923 };
6924
6925 // A DescriptorDatabase which falsely always returns foo.proto when searching
6926 // for any symbol or extension number. This shouldn't cause the
6927 // DescriptorPool to reload foo.proto if it is already loaded.
6928 class FalsePositiveDatabase : public DescriptorDatabase {
6929 public:
FalsePositiveDatabase(DescriptorDatabase * wrapped_db)6930 FalsePositiveDatabase(DescriptorDatabase* wrapped_db)
6931 : wrapped_db_(wrapped_db) {}
~FalsePositiveDatabase()6932 ~FalsePositiveDatabase() override {}
6933
6934 DescriptorDatabase* wrapped_db_;
6935
6936 // implements DescriptorDatabase ---------------------------------
FindFileByName(const std::string & filename,FileDescriptorProto * output)6937 bool FindFileByName(const std::string& filename,
6938 FileDescriptorProto* output) override {
6939 return wrapped_db_->FindFileByName(filename, output);
6940 }
FindFileContainingSymbol(const std::string & symbol_name,FileDescriptorProto * output)6941 bool FindFileContainingSymbol(const std::string& symbol_name,
6942 FileDescriptorProto* output) override {
6943 return FindFileByName("foo.proto", output);
6944 }
FindFileContainingExtension(const std::string & containing_type,int field_number,FileDescriptorProto * output)6945 bool FindFileContainingExtension(const std::string& containing_type,
6946 int field_number,
6947 FileDescriptorProto* output) override {
6948 return FindFileByName("foo.proto", output);
6949 }
6950 };
6951 };
6952
TEST_F(DatabaseBackedPoolTest,FindFileByName)6953 TEST_F(DatabaseBackedPoolTest, FindFileByName) {
6954 DescriptorPool pool(&database_);
6955
6956 const FileDescriptor* foo = pool.FindFileByName("foo.proto");
6957 ASSERT_TRUE(foo != nullptr);
6958 EXPECT_EQ("foo.proto", foo->name());
6959 ASSERT_EQ(1, foo->message_type_count());
6960 EXPECT_EQ("Foo", foo->message_type(0)->name());
6961
6962 EXPECT_EQ(foo, pool.FindFileByName("foo.proto"));
6963
6964 EXPECT_TRUE(pool.FindFileByName("no_such_file.proto") == nullptr);
6965 }
6966
TEST_F(DatabaseBackedPoolTest,FindDependencyBeforeDependent)6967 TEST_F(DatabaseBackedPoolTest, FindDependencyBeforeDependent) {
6968 DescriptorPool pool(&database_);
6969
6970 const FileDescriptor* foo = pool.FindFileByName("foo.proto");
6971 ASSERT_TRUE(foo != nullptr);
6972 EXPECT_EQ("foo.proto", foo->name());
6973 ASSERT_EQ(1, foo->message_type_count());
6974 EXPECT_EQ("Foo", foo->message_type(0)->name());
6975
6976 const FileDescriptor* bar = pool.FindFileByName("bar.proto");
6977 ASSERT_TRUE(bar != nullptr);
6978 EXPECT_EQ("bar.proto", bar->name());
6979 ASSERT_EQ(1, bar->message_type_count());
6980 EXPECT_EQ("Bar", bar->message_type(0)->name());
6981
6982 ASSERT_EQ(1, bar->dependency_count());
6983 EXPECT_EQ(foo, bar->dependency(0));
6984 }
6985
TEST_F(DatabaseBackedPoolTest,FindDependentBeforeDependency)6986 TEST_F(DatabaseBackedPoolTest, FindDependentBeforeDependency) {
6987 DescriptorPool pool(&database_);
6988
6989 const FileDescriptor* bar = pool.FindFileByName("bar.proto");
6990 ASSERT_TRUE(bar != nullptr);
6991 EXPECT_EQ("bar.proto", bar->name());
6992 ASSERT_EQ(1, bar->message_type_count());
6993 ASSERT_EQ("Bar", bar->message_type(0)->name());
6994
6995 const FileDescriptor* foo = pool.FindFileByName("foo.proto");
6996 ASSERT_TRUE(foo != nullptr);
6997 EXPECT_EQ("foo.proto", foo->name());
6998 ASSERT_EQ(1, foo->message_type_count());
6999 ASSERT_EQ("Foo", foo->message_type(0)->name());
7000
7001 ASSERT_EQ(1, bar->dependency_count());
7002 EXPECT_EQ(foo, bar->dependency(0));
7003 }
7004
TEST_F(DatabaseBackedPoolTest,FindFileContainingSymbol)7005 TEST_F(DatabaseBackedPoolTest, FindFileContainingSymbol) {
7006 DescriptorPool pool(&database_);
7007
7008 const FileDescriptor* file = pool.FindFileContainingSymbol("Foo");
7009 ASSERT_TRUE(file != nullptr);
7010 EXPECT_EQ("foo.proto", file->name());
7011 EXPECT_EQ(file, pool.FindFileByName("foo.proto"));
7012
7013 EXPECT_TRUE(pool.FindFileContainingSymbol("NoSuchSymbol") == nullptr);
7014 }
7015
TEST_F(DatabaseBackedPoolTest,FindMessageTypeByName)7016 TEST_F(DatabaseBackedPoolTest, FindMessageTypeByName) {
7017 DescriptorPool pool(&database_);
7018
7019 const Descriptor* type = pool.FindMessageTypeByName("Foo");
7020 ASSERT_TRUE(type != nullptr);
7021 EXPECT_EQ("Foo", type->name());
7022 EXPECT_EQ(type->file(), pool.FindFileByName("foo.proto"));
7023
7024 EXPECT_TRUE(pool.FindMessageTypeByName("NoSuchType") == nullptr);
7025 }
7026
TEST_F(DatabaseBackedPoolTest,FindExtensionByNumber)7027 TEST_F(DatabaseBackedPoolTest, FindExtensionByNumber) {
7028 DescriptorPool pool(&database_);
7029
7030 const Descriptor* foo = pool.FindMessageTypeByName("Foo");
7031 ASSERT_TRUE(foo != nullptr);
7032
7033 const FieldDescriptor* extension = pool.FindExtensionByNumber(foo, 5);
7034 ASSERT_TRUE(extension != nullptr);
7035 EXPECT_EQ("foo_ext", extension->name());
7036 EXPECT_EQ(extension->file(), pool.FindFileByName("bar.proto"));
7037
7038 EXPECT_TRUE(pool.FindExtensionByNumber(foo, 12) == nullptr);
7039 }
7040
TEST_F(DatabaseBackedPoolTest,FindAllExtensions)7041 TEST_F(DatabaseBackedPoolTest, FindAllExtensions) {
7042 DescriptorPool pool(&database_);
7043
7044 const Descriptor* foo = pool.FindMessageTypeByName("Foo");
7045
7046 for (int i = 0; i < 2; ++i) {
7047 // Repeat the lookup twice, to check that we get consistent
7048 // results despite the fallback database lookup mutating the pool.
7049 std::vector<const FieldDescriptor*> extensions;
7050 pool.FindAllExtensions(foo, &extensions);
7051 ASSERT_EQ(1, extensions.size());
7052 EXPECT_EQ(5, extensions[0]->number());
7053 }
7054 }
7055
TEST_F(DatabaseBackedPoolTest,ErrorWithoutErrorCollector)7056 TEST_F(DatabaseBackedPoolTest, ErrorWithoutErrorCollector) {
7057 ErrorDescriptorDatabase error_database;
7058 DescriptorPool pool(&error_database);
7059
7060 std::vector<std::string> errors;
7061
7062 {
7063 ScopedMemoryLog log;
7064 EXPECT_TRUE(pool.FindFileByName("error.proto") == nullptr);
7065 errors = log.GetMessages(ERROR);
7066 }
7067
7068 EXPECT_FALSE(errors.empty());
7069 }
7070
TEST_F(DatabaseBackedPoolTest,ErrorWithErrorCollector)7071 TEST_F(DatabaseBackedPoolTest, ErrorWithErrorCollector) {
7072 ErrorDescriptorDatabase error_database;
7073 MockErrorCollector error_collector;
7074 DescriptorPool pool(&error_database, &error_collector);
7075
7076 EXPECT_TRUE(pool.FindFileByName("error.proto") == nullptr);
7077 EXPECT_EQ(
7078 "error.proto: error2.proto: IMPORT: File recursively imports itself: "
7079 "error.proto -> error2.proto -> error.proto\n"
7080 "error2.proto: error.proto: IMPORT: Import \"error.proto\" was not "
7081 "found or had errors.\n"
7082 "error.proto: error2.proto: IMPORT: Import \"error2.proto\" was not "
7083 "found or had errors.\n",
7084 error_collector.text_);
7085 }
7086
TEST_F(DatabaseBackedPoolTest,UndeclaredDependencyOnUnbuiltType)7087 TEST_F(DatabaseBackedPoolTest, UndeclaredDependencyOnUnbuiltType) {
7088 // Check that we find and report undeclared dependencies on types that exist
7089 // in the descriptor database but that have not not been built yet.
7090 MockErrorCollector error_collector;
7091 DescriptorPool pool(&database_, &error_collector);
7092 EXPECT_TRUE(pool.FindMessageTypeByName("Baz") == nullptr);
7093 EXPECT_EQ(
7094 "baz.proto: Baz.foo: TYPE: \"Foo\" seems to be defined in \"foo.proto\", "
7095 "which is not imported by \"baz.proto\". To use it here, please add "
7096 "the necessary import.\n",
7097 error_collector.text_);
7098 }
7099
TEST_F(DatabaseBackedPoolTest,RollbackAfterError)7100 TEST_F(DatabaseBackedPoolTest, RollbackAfterError) {
7101 // Make sure that all traces of bad types are removed from the pool. This used
7102 // to be b/4529436, due to the fact that a symbol resolution failure could
7103 // potentially cause another file to be recursively built, which would trigger
7104 // a checkpoint _past_ possibly invalid symbols.
7105 // Baz is defined in the database, but the file is invalid because it is
7106 // missing a necessary import.
7107 DescriptorPool pool(&database_);
7108 EXPECT_TRUE(pool.FindMessageTypeByName("Baz") == nullptr);
7109 // Make sure that searching again for the file or the type fails.
7110 EXPECT_TRUE(pool.FindFileByName("baz.proto") == nullptr);
7111 EXPECT_TRUE(pool.FindMessageTypeByName("Baz") == nullptr);
7112 }
7113
TEST_F(DatabaseBackedPoolTest,UnittestProto)7114 TEST_F(DatabaseBackedPoolTest, UnittestProto) {
7115 // Try to load all of unittest.proto from a DescriptorDatabase. This should
7116 // thoroughly test all paths through DescriptorBuilder to insure that there
7117 // are no deadlocking problems when pool_->mutex_ is non-null.
7118 const FileDescriptor* original_file =
7119 protobuf_unittest::TestAllTypes::descriptor()->file();
7120
7121 DescriptorPoolDatabase database(*DescriptorPool::generated_pool());
7122 DescriptorPool pool(&database);
7123 const FileDescriptor* file_from_database =
7124 pool.FindFileByName(original_file->name());
7125
7126 ASSERT_TRUE(file_from_database != nullptr);
7127
7128 FileDescriptorProto original_file_proto;
7129 original_file->CopyTo(&original_file_proto);
7130
7131 FileDescriptorProto file_from_database_proto;
7132 file_from_database->CopyTo(&file_from_database_proto);
7133
7134 EXPECT_EQ(original_file_proto.DebugString(),
7135 file_from_database_proto.DebugString());
7136
7137 // Also verify that CopyTo() did not omit any information.
7138 EXPECT_EQ(original_file->DebugString(), file_from_database->DebugString());
7139 }
7140
TEST_F(DatabaseBackedPoolTest,DoesntRetryDbUnnecessarily)7141 TEST_F(DatabaseBackedPoolTest, DoesntRetryDbUnnecessarily) {
7142 // Searching for a child of an existing descriptor should never fall back
7143 // to the DescriptorDatabase even if it isn't found, because we know all
7144 // children are already loaded.
7145 CallCountingDatabase call_counter(&database_);
7146 DescriptorPool pool(&call_counter);
7147
7148 const FileDescriptor* file = pool.FindFileByName("foo.proto");
7149 ASSERT_TRUE(file != nullptr);
7150 const Descriptor* foo = pool.FindMessageTypeByName("Foo");
7151 ASSERT_TRUE(foo != nullptr);
7152 const EnumDescriptor* test_enum = pool.FindEnumTypeByName("TestEnum");
7153 ASSERT_TRUE(test_enum != nullptr);
7154 const ServiceDescriptor* test_service = pool.FindServiceByName("TestService");
7155 ASSERT_TRUE(test_service != nullptr);
7156
7157 EXPECT_NE(0, call_counter.call_count_);
7158 call_counter.Clear();
7159
7160 EXPECT_TRUE(foo->FindFieldByName("no_such_field") == nullptr);
7161 EXPECT_TRUE(foo->FindExtensionByName("no_such_extension") == nullptr);
7162 EXPECT_TRUE(foo->FindNestedTypeByName("NoSuchMessageType") == nullptr);
7163 EXPECT_TRUE(foo->FindEnumTypeByName("NoSuchEnumType") == nullptr);
7164 EXPECT_TRUE(foo->FindEnumValueByName("NO_SUCH_VALUE") == nullptr);
7165 EXPECT_TRUE(test_enum->FindValueByName("NO_SUCH_VALUE") == nullptr);
7166 EXPECT_TRUE(test_service->FindMethodByName("NoSuchMethod") == nullptr);
7167
7168 EXPECT_TRUE(file->FindMessageTypeByName("NoSuchMessageType") == nullptr);
7169 EXPECT_TRUE(file->FindEnumTypeByName("NoSuchEnumType") == nullptr);
7170 EXPECT_TRUE(file->FindEnumValueByName("NO_SUCH_VALUE") == nullptr);
7171 EXPECT_TRUE(file->FindServiceByName("NO_SUCH_VALUE") == nullptr);
7172 EXPECT_TRUE(file->FindExtensionByName("no_such_extension") == nullptr);
7173
7174 EXPECT_TRUE(pool.FindFileContainingSymbol("Foo.no.such.field") == nullptr);
7175 EXPECT_TRUE(pool.FindFileContainingSymbol("Foo.no_such_field") == nullptr);
7176 EXPECT_TRUE(pool.FindMessageTypeByName("Foo.NoSuchMessageType") == nullptr);
7177 EXPECT_TRUE(pool.FindFieldByName("Foo.no_such_field") == nullptr);
7178 EXPECT_TRUE(pool.FindExtensionByName("Foo.no_such_extension") == nullptr);
7179 EXPECT_TRUE(pool.FindEnumTypeByName("Foo.NoSuchEnumType") == nullptr);
7180 EXPECT_TRUE(pool.FindEnumValueByName("Foo.NO_SUCH_VALUE") == nullptr);
7181 EXPECT_TRUE(pool.FindMethodByName("TestService.NoSuchMethod") == nullptr);
7182
7183 EXPECT_EQ(0, call_counter.call_count_);
7184 }
7185
TEST_F(DatabaseBackedPoolTest,DoesntReloadFilesUncesessarily)7186 TEST_F(DatabaseBackedPoolTest, DoesntReloadFilesUncesessarily) {
7187 // If FindFileContainingSymbol() or FindFileContainingExtension() return a
7188 // file that is already in the DescriptorPool, it should not attempt to
7189 // reload the file.
7190 FalsePositiveDatabase false_positive_database(&database_);
7191 MockErrorCollector error_collector;
7192 DescriptorPool pool(&false_positive_database, &error_collector);
7193
7194 // First make sure foo.proto is loaded.
7195 const Descriptor* foo = pool.FindMessageTypeByName("Foo");
7196 ASSERT_TRUE(foo != nullptr);
7197
7198 // Try inducing false positives.
7199 EXPECT_TRUE(pool.FindMessageTypeByName("NoSuchSymbol") == nullptr);
7200 EXPECT_TRUE(pool.FindExtensionByNumber(foo, 22) == nullptr);
7201
7202 // No errors should have been reported. (If foo.proto was incorrectly
7203 // loaded multiple times, errors would have been reported.)
7204 EXPECT_EQ("", error_collector.text_);
7205 }
7206
7207 // DescriptorDatabase that attempts to induce exponentially-bad performance
7208 // in DescriptorPool. For every positive N, the database contains a file
7209 // fileN.proto, which defines a message MessageN, which contains fields of
7210 // type MessageK for all K in [0,N). Message0 is not defined anywhere
7211 // (file0.proto exists, but is empty), so every other file and message type
7212 // will fail to build.
7213 //
7214 // If the DescriptorPool is not careful to memoize errors, an attempt to
7215 // build a descriptor for MessageN can require O(2^N) time.
7216 class ExponentialErrorDatabase : public DescriptorDatabase {
7217 public:
ExponentialErrorDatabase()7218 ExponentialErrorDatabase() {}
~ExponentialErrorDatabase()7219 ~ExponentialErrorDatabase() override {}
7220
7221 // implements DescriptorDatabase ---------------------------------
FindFileByName(const std::string & filename,FileDescriptorProto * output)7222 bool FindFileByName(const std::string& filename,
7223 FileDescriptorProto* output) override {
7224 int file_num = -1;
7225 FullMatch(filename, "file", ".proto", &file_num);
7226 if (file_num > -1) {
7227 return PopulateFile(file_num, output);
7228 } else {
7229 return false;
7230 }
7231 }
FindFileContainingSymbol(const std::string & symbol_name,FileDescriptorProto * output)7232 bool FindFileContainingSymbol(const std::string& symbol_name,
7233 FileDescriptorProto* output) override {
7234 int file_num = -1;
7235 FullMatch(symbol_name, "Message", "", &file_num);
7236 if (file_num > 0) {
7237 return PopulateFile(file_num, output);
7238 } else {
7239 return false;
7240 }
7241 }
FindFileContainingExtension(const std::string & containing_type,int field_number,FileDescriptorProto * output)7242 bool FindFileContainingExtension(const std::string& containing_type,
7243 int field_number,
7244 FileDescriptorProto* output) override {
7245 return false;
7246 }
7247
7248 private:
FullMatch(const std::string & name,const std::string & begin_with,const std::string & end_with,int * file_num)7249 void FullMatch(const std::string& name, const std::string& begin_with,
7250 const std::string& end_with, int* file_num) {
7251 int begin_size = begin_with.size();
7252 int end_size = end_with.size();
7253 if (name.substr(0, begin_size) != begin_with ||
7254 name.substr(name.size() - end_size, end_size) != end_with) {
7255 return;
7256 }
7257 safe_strto32(
7258 name.substr(begin_size, name.size() - end_size - begin_size), file_num);
7259 }
7260
PopulateFile(int file_num,FileDescriptorProto * output)7261 bool PopulateFile(int file_num, FileDescriptorProto* output) {
7262 GOOGLE_CHECK_GE(file_num, 0);
7263 output->Clear();
7264 output->set_name(strings::Substitute("file$0.proto", file_num));
7265 // file0.proto doesn't define Message0
7266 if (file_num > 0) {
7267 DescriptorProto* message = output->add_message_type();
7268 message->set_name(strings::Substitute("Message$0", file_num));
7269 for (int i = 0; i < file_num; ++i) {
7270 output->add_dependency(strings::Substitute("file$0.proto", i));
7271 FieldDescriptorProto* field = message->add_field();
7272 field->set_name(strings::Substitute("field$0", i));
7273 field->set_number(i);
7274 field->set_label(FieldDescriptorProto::LABEL_OPTIONAL);
7275 field->set_type(FieldDescriptorProto::TYPE_MESSAGE);
7276 field->set_type_name(strings::Substitute("Message$0", i));
7277 }
7278 }
7279 return true;
7280 }
7281 };
7282
TEST_F(DatabaseBackedPoolTest,DoesntReloadKnownBadFiles)7283 TEST_F(DatabaseBackedPoolTest, DoesntReloadKnownBadFiles) {
7284 ExponentialErrorDatabase error_database;
7285 DescriptorPool pool(&error_database);
7286
7287 GOOGLE_LOG(INFO) << "A timeout in this test probably indicates a real bug.";
7288
7289 EXPECT_TRUE(pool.FindFileByName("file40.proto") == nullptr);
7290 EXPECT_TRUE(pool.FindMessageTypeByName("Message40") == nullptr);
7291 }
7292
TEST_F(DatabaseBackedPoolTest,DoesntFallbackOnWrongType)7293 TEST_F(DatabaseBackedPoolTest, DoesntFallbackOnWrongType) {
7294 // If a lookup finds a symbol of the wrong type (e.g. we pass a type name
7295 // to FindFieldByName()), we should fail fast, without checking the fallback
7296 // database.
7297 CallCountingDatabase call_counter(&database_);
7298 DescriptorPool pool(&call_counter);
7299
7300 const FileDescriptor* file = pool.FindFileByName("foo.proto");
7301 ASSERT_TRUE(file != nullptr);
7302 const Descriptor* foo = pool.FindMessageTypeByName("Foo");
7303 ASSERT_TRUE(foo != nullptr);
7304 const EnumDescriptor* test_enum = pool.FindEnumTypeByName("TestEnum");
7305 ASSERT_TRUE(test_enum != nullptr);
7306
7307 EXPECT_NE(0, call_counter.call_count_);
7308 call_counter.Clear();
7309
7310 EXPECT_TRUE(pool.FindMessageTypeByName("TestEnum") == nullptr);
7311 EXPECT_TRUE(pool.FindFieldByName("Foo") == nullptr);
7312 EXPECT_TRUE(pool.FindExtensionByName("Foo") == nullptr);
7313 EXPECT_TRUE(pool.FindEnumTypeByName("Foo") == nullptr);
7314 EXPECT_TRUE(pool.FindEnumValueByName("Foo") == nullptr);
7315 EXPECT_TRUE(pool.FindServiceByName("Foo") == nullptr);
7316 EXPECT_TRUE(pool.FindMethodByName("Foo") == nullptr);
7317
7318 EXPECT_EQ(0, call_counter.call_count_);
7319 }
7320
7321 // ===================================================================
7322
7323 class AbortingErrorCollector : public DescriptorPool::ErrorCollector {
7324 public:
AbortingErrorCollector()7325 AbortingErrorCollector() {}
7326
AddError(const std::string & filename,const std::string & element_name,const Message * message,ErrorLocation location,const std::string & error_message)7327 void AddError(const std::string& filename, const std::string& element_name,
7328 const Message* message, ErrorLocation location,
7329 const std::string& error_message) override {
7330 GOOGLE_LOG(FATAL) << "AddError() called unexpectedly: " << filename << " ["
7331 << element_name << "]: " << error_message;
7332 }
7333
7334 private:
7335 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(AbortingErrorCollector);
7336 };
7337
7338 // A source tree containing only one file.
7339 class SingletonSourceTree : public compiler::SourceTree {
7340 public:
SingletonSourceTree(const std::string & filename,const std::string & contents)7341 SingletonSourceTree(const std::string& filename, const std::string& contents)
7342 : filename_(filename), contents_(contents) {}
7343
Open(const std::string & filename)7344 io::ZeroCopyInputStream* Open(const std::string& filename) override {
7345 return filename == filename_
7346 ? new io::ArrayInputStream(contents_.data(), contents_.size())
7347 : nullptr;
7348 }
7349
7350 private:
7351 const std::string filename_;
7352 const std::string contents_;
7353
7354 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SingletonSourceTree);
7355 };
7356
7357 const char* const kSourceLocationTestInput =
7358 "syntax = \"proto2\";\n"
7359 "option java_package = \"com.foo.bar\";\n"
7360 "option (test_file_opt) = \"foobar\";\n"
7361 "message A {\n"
7362 " option (test_msg_opt) = \"foobar\";\n"
7363 " optional int32 a = 1 [deprecated = true];\n"
7364 " message B {\n"
7365 " required double b = 1 [(test_field_opt) = \"foobar\"];\n"
7366 " }\n"
7367 " oneof c {\n"
7368 " option (test_oneof_opt) = \"foobar\";\n"
7369 " string d = 2;\n"
7370 " string e = 3;\n"
7371 " string f = 4;\n"
7372 " }\n"
7373 "}\n"
7374 "enum Indecision {\n"
7375 " option (test_enum_opt) = 21;\n"
7376 " option (test_enum_opt) = 42;\n"
7377 " option (test_enum_opt) = 63;\n"
7378 " YES = 1 [(test_enumval_opt).a = 100];\n"
7379 " NO = 2 [(test_enumval_opt) = {a:200}];\n"
7380 " MAYBE = 3;\n"
7381 "}\n"
7382 "service S {\n"
7383 " option (test_svc_opt) = {a:100};\n"
7384 " option (test_svc_opt) = {a:200};\n"
7385 " option (test_svc_opt) = {a:300};\n"
7386 " rpc Method(A) returns (A.B);\n"
7387 // Put an empty line here to make the source location range match.
7388 "\n"
7389 " rpc OtherMethod(A) returns (A) {\n"
7390 " option deprecated = true;\n"
7391 " option (test_method_opt) = \"foobar\";\n"
7392 " }\n"
7393 "}\n"
7394 "message MessageWithExtensions {\n"
7395 " extensions 1000 to 2000, 2001 to max [(test_ext_opt) = \"foobar\"];\n"
7396 "}\n"
7397 "extend MessageWithExtensions {\n"
7398 " repeated int32 int32_extension = 1001 [packed=true];\n"
7399 "}\n"
7400 "message C {\n"
7401 " extend MessageWithExtensions {\n"
7402 " optional C message_extension = 1002;\n"
7403 " }\n"
7404 "}\n"
7405 "import \"google/protobuf/descriptor.proto\";\n"
7406 "extend google.protobuf.FileOptions {\n"
7407 " optional string test_file_opt = 10101;\n"
7408 "}\n"
7409 "extend google.protobuf.MessageOptions {\n"
7410 " optional string test_msg_opt = 10101;\n"
7411 "}\n"
7412 "extend google.protobuf.FieldOptions {\n"
7413 " optional string test_field_opt = 10101;\n"
7414 "}\n"
7415 "extend google.protobuf.EnumOptions {\n"
7416 " repeated int32 test_enum_opt = 10101;\n"
7417 "}\n"
7418 "extend google.protobuf.EnumValueOptions {\n"
7419 " optional A test_enumval_opt = 10101;\n"
7420 "}\n"
7421 "extend google.protobuf.ServiceOptions {\n"
7422 " repeated A test_svc_opt = 10101;\n"
7423 "}\n"
7424 "extend google.protobuf.MethodOptions {\n"
7425 " optional string test_method_opt = 10101;\n"
7426 "}\n"
7427 "extend google.protobuf.OneofOptions {\n"
7428 " optional string test_oneof_opt = 10101;\n"
7429 "}\n"
7430 "extend google.protobuf.ExtensionRangeOptions {\n"
7431 " optional string test_ext_opt = 10101;\n"
7432 "}\n";
7433
7434 class SourceLocationTest : public testing::Test {
7435 public:
SourceLocationTest()7436 SourceLocationTest()
7437 : source_tree_("/test/test.proto", kSourceLocationTestInput),
7438 simple_db_(),
7439 source_tree_db_(&source_tree_),
7440 merged_db_(&simple_db_, &source_tree_db_),
7441 pool_(&merged_db_, &collector_) {
7442 // we need descriptor.proto to be accessible by the pool
7443 // since our test file imports it
7444 FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto_);
7445 simple_db_.Add(file_proto_);
7446 }
7447
PrintSourceLocation(const SourceLocation & loc)7448 static std::string PrintSourceLocation(const SourceLocation& loc) {
7449 return strings::Substitute("$0:$1-$2:$3", 1 + loc.start_line,
7450 1 + loc.start_column, 1 + loc.end_line,
7451 1 + loc.end_column);
7452 }
7453
7454 private:
7455 FileDescriptorProto file_proto_;
7456 AbortingErrorCollector collector_;
7457 SingletonSourceTree source_tree_;
7458 SimpleDescriptorDatabase simple_db_; // contains descriptor.proto
7459 compiler::SourceTreeDescriptorDatabase source_tree_db_; // loads test.proto
7460 MergedDescriptorDatabase merged_db_; // combines above two dbs
7461
7462 protected:
7463 DescriptorPool pool_;
7464
7465 // tag number of all custom options in above test file
7466 static constexpr int kCustomOptionFieldNumber = 10101;
7467 // tag number of field "a" in message type "A" in above test file
7468 static constexpr int kAFieldNumber = 1;
7469 };
7470
7471 // TODO(adonovan): implement support for option fields and for
7472 // subparts of declarations.
7473
TEST_F(SourceLocationTest,GetSourceLocation)7474 TEST_F(SourceLocationTest, GetSourceLocation) {
7475 SourceLocation loc;
7476
7477 const FileDescriptor* file_desc =
7478 GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto"));
7479
7480 const Descriptor* a_desc = file_desc->FindMessageTypeByName("A");
7481 EXPECT_TRUE(a_desc->GetSourceLocation(&loc));
7482 EXPECT_EQ("4:1-16:2", PrintSourceLocation(loc));
7483
7484 const Descriptor* a_b_desc = a_desc->FindNestedTypeByName("B");
7485 EXPECT_TRUE(a_b_desc->GetSourceLocation(&loc));
7486 EXPECT_EQ("7:3-9:4", PrintSourceLocation(loc));
7487
7488 const EnumDescriptor* e_desc = file_desc->FindEnumTypeByName("Indecision");
7489 EXPECT_TRUE(e_desc->GetSourceLocation(&loc));
7490 EXPECT_EQ("17:1-24:2", PrintSourceLocation(loc));
7491
7492 const EnumValueDescriptor* yes_desc = e_desc->FindValueByName("YES");
7493 EXPECT_TRUE(yes_desc->GetSourceLocation(&loc));
7494 EXPECT_EQ("21:3-21:42", PrintSourceLocation(loc));
7495
7496 const ServiceDescriptor* s_desc = file_desc->FindServiceByName("S");
7497 EXPECT_TRUE(s_desc->GetSourceLocation(&loc));
7498 EXPECT_EQ("25:1-35:2", PrintSourceLocation(loc));
7499
7500 const MethodDescriptor* m_desc = s_desc->FindMethodByName("Method");
7501 EXPECT_TRUE(m_desc->GetSourceLocation(&loc));
7502 EXPECT_EQ("29:3-29:31", PrintSourceLocation(loc));
7503 }
7504
TEST_F(SourceLocationTest,ExtensionSourceLocation)7505 TEST_F(SourceLocationTest, ExtensionSourceLocation) {
7506 SourceLocation loc;
7507
7508 const FileDescriptor* file_desc =
7509 GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto"));
7510
7511 const FieldDescriptor* int32_extension_desc =
7512 file_desc->FindExtensionByName("int32_extension");
7513 EXPECT_TRUE(int32_extension_desc->GetSourceLocation(&loc));
7514 EXPECT_EQ("40:3-40:55", PrintSourceLocation(loc));
7515
7516 const Descriptor* c_desc = file_desc->FindMessageTypeByName("C");
7517 EXPECT_TRUE(c_desc->GetSourceLocation(&loc));
7518 EXPECT_EQ("42:1-46:2", PrintSourceLocation(loc));
7519
7520 const FieldDescriptor* message_extension_desc =
7521 c_desc->FindExtensionByName("message_extension");
7522 EXPECT_TRUE(message_extension_desc->GetSourceLocation(&loc));
7523 EXPECT_EQ("44:5-44:41", PrintSourceLocation(loc));
7524 }
TEST_F(SourceLocationTest,InterpretedOptionSourceLocation)7525 TEST_F(SourceLocationTest, InterpretedOptionSourceLocation) {
7526 // This one's a doozy. It checks every kind of option, including
7527 // extension range options.
7528
7529 // We are verifying that the file's source info contains correct
7530 // info for interpreted options and that it does *not* contain
7531 // any info for corresponding uninterpreted option path.
7532
7533 SourceLocation loc;
7534
7535 const FileDescriptor* file_desc =
7536 GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto"));
7537
7538 // File options
7539 {
7540 int path[] = {FileDescriptorProto::kOptionsFieldNumber,
7541 FileOptions::kJavaPackageFieldNumber};
7542 int unint[] = {FileDescriptorProto::kOptionsFieldNumber,
7543 FileOptions::kUninterpretedOptionFieldNumber, 0};
7544
7545 std::vector<int> vpath(path, path + 2);
7546 EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
7547 EXPECT_EQ("2:1-2:37", PrintSourceLocation(loc));
7548
7549 std::vector<int> vunint(unint, unint + 3);
7550 EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
7551 }
7552 {
7553 int path[] = {FileDescriptorProto::kOptionsFieldNumber,
7554 kCustomOptionFieldNumber};
7555 int unint[] = {FileDescriptorProto::kOptionsFieldNumber,
7556 FileOptions::kUninterpretedOptionFieldNumber, 1};
7557 std::vector<int> vpath(path, path + 2);
7558 EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
7559 EXPECT_EQ("3:1-3:35", PrintSourceLocation(loc));
7560
7561 std::vector<int> vunint(unint, unint + 3);
7562 EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
7563 }
7564
7565 // Message option
7566 {
7567 int path[] = {FileDescriptorProto::kMessageTypeFieldNumber, 0,
7568 DescriptorProto::kOptionsFieldNumber,
7569 kCustomOptionFieldNumber};
7570 int unint[] = {FileDescriptorProto::kMessageTypeFieldNumber, 0,
7571 DescriptorProto::kOptionsFieldNumber,
7572 MessageOptions::kUninterpretedOptionFieldNumber, 0};
7573 std::vector<int> vpath(path, path + 4);
7574 EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
7575 EXPECT_EQ("5:3-5:36", PrintSourceLocation(loc));
7576
7577 std::vector<int> vunint(unint, unint + 5);
7578 EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
7579 }
7580
7581 // Field option
7582 {
7583 int path[] = {FileDescriptorProto::kMessageTypeFieldNumber,
7584 0,
7585 DescriptorProto::kFieldFieldNumber,
7586 0,
7587 FieldDescriptorProto::kOptionsFieldNumber,
7588 FieldOptions::kDeprecatedFieldNumber};
7589 int unint[] = {FileDescriptorProto::kMessageTypeFieldNumber,
7590 0,
7591 DescriptorProto::kFieldFieldNumber,
7592 0,
7593 FieldDescriptorProto::kOptionsFieldNumber,
7594 FieldOptions::kUninterpretedOptionFieldNumber,
7595 0};
7596 std::vector<int> vpath(path, path + 6);
7597 EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
7598 EXPECT_EQ("6:25-6:42", PrintSourceLocation(loc));
7599
7600 std::vector<int> vunint(unint, unint + 7);
7601 EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
7602 }
7603
7604 // Nested message option
7605 {
7606 int path[] = {
7607 FileDescriptorProto::kMessageTypeFieldNumber, 0,
7608 DescriptorProto::kNestedTypeFieldNumber, 0,
7609 DescriptorProto::kFieldFieldNumber, 0,
7610 FieldDescriptorProto::kOptionsFieldNumber, kCustomOptionFieldNumber};
7611 int unint[] = {FileDescriptorProto::kMessageTypeFieldNumber,
7612 0,
7613 DescriptorProto::kNestedTypeFieldNumber,
7614 0,
7615 DescriptorProto::kFieldFieldNumber,
7616 0,
7617 FieldDescriptorProto::kOptionsFieldNumber,
7618 FieldOptions::kUninterpretedOptionFieldNumber,
7619 0};
7620 std::vector<int> vpath(path, path + 8);
7621 EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
7622 EXPECT_EQ("8:28-8:55", PrintSourceLocation(loc));
7623
7624 std::vector<int> vunint(unint, unint + 9);
7625 EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
7626 }
7627
7628 // One-of option
7629 {
7630 int path[] = {
7631 FileDescriptorProto::kMessageTypeFieldNumber, 0,
7632 DescriptorProto::kOneofDeclFieldNumber, 0,
7633 OneofDescriptorProto::kOptionsFieldNumber, kCustomOptionFieldNumber};
7634 int unint[] = {FileDescriptorProto::kMessageTypeFieldNumber,
7635 0,
7636 DescriptorProto::kOneofDeclFieldNumber,
7637 0,
7638 OneofDescriptorProto::kOptionsFieldNumber,
7639 OneofOptions::kUninterpretedOptionFieldNumber,
7640 0};
7641 std::vector<int> vpath(path, path + 6);
7642 EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
7643 EXPECT_EQ("11:5-11:40", PrintSourceLocation(loc));
7644
7645 std::vector<int> vunint(unint, unint + 7);
7646 EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
7647 }
7648
7649 // Enum option, repeated options
7650 {
7651 int path[] = {FileDescriptorProto::kEnumTypeFieldNumber, 0,
7652 EnumDescriptorProto::kOptionsFieldNumber,
7653 kCustomOptionFieldNumber, 0};
7654 int unint[] = {FileDescriptorProto::kEnumTypeFieldNumber, 0,
7655 EnumDescriptorProto::kOptionsFieldNumber,
7656 EnumOptions::kUninterpretedOptionFieldNumber, 0};
7657 std::vector<int> vpath(path, path + 5);
7658 EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
7659 EXPECT_EQ("18:3-18:31", PrintSourceLocation(loc));
7660
7661 std::vector<int> vunint(unint, unint + 5);
7662 EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
7663 }
7664 {
7665 int path[] = {FileDescriptorProto::kEnumTypeFieldNumber, 0,
7666 EnumDescriptorProto::kOptionsFieldNumber,
7667 kCustomOptionFieldNumber, 1};
7668 int unint[] = {FileDescriptorProto::kEnumTypeFieldNumber, 0,
7669 EnumDescriptorProto::kOptionsFieldNumber,
7670 EnumOptions::kUninterpretedOptionFieldNumber, 1};
7671 std::vector<int> vpath(path, path + 5);
7672 EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
7673 EXPECT_EQ("19:3-19:31", PrintSourceLocation(loc));
7674
7675 std::vector<int> vunint(unint, unint + 5);
7676 EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
7677 }
7678 {
7679 int path[] = {FileDescriptorProto::kEnumTypeFieldNumber, 0,
7680 EnumDescriptorProto::kOptionsFieldNumber,
7681 kCustomOptionFieldNumber, 2};
7682 int unint[] = {FileDescriptorProto::kEnumTypeFieldNumber, 0,
7683 EnumDescriptorProto::kOptionsFieldNumber,
7684 OneofOptions::kUninterpretedOptionFieldNumber, 2};
7685 std::vector<int> vpath(path, path + 5);
7686 EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
7687 EXPECT_EQ("20:3-20:31", PrintSourceLocation(loc));
7688
7689 std::vector<int> vunint(unint, unint + 5);
7690 EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
7691 }
7692
7693 // Enum value options
7694 {
7695 // option w/ message type that directly sets field
7696 int path[] = {FileDescriptorProto::kEnumTypeFieldNumber,
7697 0,
7698 EnumDescriptorProto::kValueFieldNumber,
7699 0,
7700 EnumValueDescriptorProto::kOptionsFieldNumber,
7701 kCustomOptionFieldNumber,
7702 kAFieldNumber};
7703 int unint[] = {FileDescriptorProto::kEnumTypeFieldNumber,
7704 0,
7705 EnumDescriptorProto::kValueFieldNumber,
7706 0,
7707 EnumValueDescriptorProto::kOptionsFieldNumber,
7708 EnumValueOptions::kUninterpretedOptionFieldNumber,
7709 0};
7710 std::vector<int> vpath(path, path + 7);
7711 EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
7712 EXPECT_EQ("21:14-21:40", PrintSourceLocation(loc));
7713
7714 std::vector<int> vunint(unint, unint + 7);
7715 EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
7716 }
7717 {
7718 int path[] = {FileDescriptorProto::kEnumTypeFieldNumber,
7719 0,
7720 EnumDescriptorProto::kValueFieldNumber,
7721 1,
7722 EnumValueDescriptorProto::kOptionsFieldNumber,
7723 kCustomOptionFieldNumber};
7724 int unint[] = {FileDescriptorProto::kEnumTypeFieldNumber,
7725 0,
7726 EnumDescriptorProto::kValueFieldNumber,
7727 1,
7728 EnumValueDescriptorProto::kOptionsFieldNumber,
7729 EnumValueOptions::kUninterpretedOptionFieldNumber,
7730 0};
7731 std::vector<int> vpath(path, path + 6);
7732 EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
7733 EXPECT_EQ("22:14-22:42", PrintSourceLocation(loc));
7734
7735 std::vector<int> vunint(unint, unint + 7);
7736 EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
7737 }
7738
7739 // Service option, repeated options
7740 {
7741 int path[] = {FileDescriptorProto::kServiceFieldNumber, 0,
7742 ServiceDescriptorProto::kOptionsFieldNumber,
7743 kCustomOptionFieldNumber, 0};
7744 int unint[] = {FileDescriptorProto::kServiceFieldNumber, 0,
7745 ServiceDescriptorProto::kOptionsFieldNumber,
7746 ServiceOptions::kUninterpretedOptionFieldNumber, 0};
7747 std::vector<int> vpath(path, path + 5);
7748 EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
7749 EXPECT_EQ("26:3-26:35", PrintSourceLocation(loc));
7750
7751 std::vector<int> vunint(unint, unint + 5);
7752 EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
7753 }
7754 {
7755 int path[] = {FileDescriptorProto::kServiceFieldNumber, 0,
7756 ServiceDescriptorProto::kOptionsFieldNumber,
7757 kCustomOptionFieldNumber, 1};
7758 int unint[] = {FileDescriptorProto::kServiceFieldNumber, 0,
7759 ServiceDescriptorProto::kOptionsFieldNumber,
7760 ServiceOptions::kUninterpretedOptionFieldNumber, 1};
7761 std::vector<int> vpath(path, path + 5);
7762 EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
7763 EXPECT_EQ("27:3-27:35", PrintSourceLocation(loc));
7764
7765 std::vector<int> vunint(unint, unint + 5);
7766 EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
7767 }
7768 {
7769 int path[] = {FileDescriptorProto::kServiceFieldNumber, 0,
7770 ServiceDescriptorProto::kOptionsFieldNumber,
7771 kCustomOptionFieldNumber, 2};
7772 int unint[] = {FileDescriptorProto::kServiceFieldNumber, 0,
7773 ServiceDescriptorProto::kOptionsFieldNumber,
7774 ServiceOptions::kUninterpretedOptionFieldNumber, 2};
7775 std::vector<int> vpath(path, path + 5);
7776 EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
7777 EXPECT_EQ("28:3-28:35", PrintSourceLocation(loc));
7778
7779 std::vector<int> vunint(unint, unint + 5);
7780 EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
7781 }
7782
7783 // Method options
7784 {
7785 int path[] = {FileDescriptorProto::kServiceFieldNumber,
7786 0,
7787 ServiceDescriptorProto::kMethodFieldNumber,
7788 1,
7789 MethodDescriptorProto::kOptionsFieldNumber,
7790 MethodOptions::kDeprecatedFieldNumber};
7791 int unint[] = {FileDescriptorProto::kServiceFieldNumber,
7792 0,
7793 ServiceDescriptorProto::kMethodFieldNumber,
7794 1,
7795 MethodDescriptorProto::kOptionsFieldNumber,
7796 MethodOptions::kUninterpretedOptionFieldNumber,
7797 0};
7798 std::vector<int> vpath(path, path + 6);
7799 EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
7800 EXPECT_EQ("32:5-32:30", PrintSourceLocation(loc));
7801
7802 std::vector<int> vunint(unint, unint + 7);
7803 EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
7804 }
7805 {
7806 int path[] = {
7807 FileDescriptorProto::kServiceFieldNumber, 0,
7808 ServiceDescriptorProto::kMethodFieldNumber, 1,
7809 MethodDescriptorProto::kOptionsFieldNumber, kCustomOptionFieldNumber};
7810 int unint[] = {FileDescriptorProto::kServiceFieldNumber,
7811 0,
7812 ServiceDescriptorProto::kMethodFieldNumber,
7813 1,
7814 MethodDescriptorProto::kOptionsFieldNumber,
7815 MethodOptions::kUninterpretedOptionFieldNumber,
7816 1};
7817 std::vector<int> vpath(path, path + 6);
7818 EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
7819 EXPECT_EQ("33:5-33:41", PrintSourceLocation(loc));
7820
7821 std::vector<int> vunint(unint, unint + 7);
7822 EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
7823 }
7824
7825 // Extension range options
7826 {
7827 int path[] = {FileDescriptorProto::kMessageTypeFieldNumber, 1,
7828 DescriptorProto::kExtensionRangeFieldNumber, 0,
7829 DescriptorProto_ExtensionRange::kOptionsFieldNumber};
7830 std::vector<int> vpath(path, path + 5);
7831 EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
7832 EXPECT_EQ("37:40-37:67", PrintSourceLocation(loc));
7833 }
7834 {
7835 int path[] = {FileDescriptorProto::kMessageTypeFieldNumber,
7836 1,
7837 DescriptorProto::kExtensionRangeFieldNumber,
7838 0,
7839 DescriptorProto_ExtensionRange::kOptionsFieldNumber,
7840 kCustomOptionFieldNumber};
7841 int unint[] = {FileDescriptorProto::kMessageTypeFieldNumber,
7842 1,
7843 DescriptorProto::kExtensionRangeFieldNumber,
7844 0,
7845 DescriptorProto_ExtensionRange::kOptionsFieldNumber,
7846 ExtensionRangeOptions::kUninterpretedOptionFieldNumber,
7847 0};
7848 std::vector<int> vpath(path, path + 6);
7849 EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
7850 EXPECT_EQ("37:41-37:66", PrintSourceLocation(loc));
7851
7852 std::vector<int> vunint(unint, unint + 7);
7853 EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
7854 }
7855 {
7856 int path[] = {FileDescriptorProto::kMessageTypeFieldNumber,
7857 1,
7858 DescriptorProto::kExtensionRangeFieldNumber,
7859 1,
7860 DescriptorProto_ExtensionRange::kOptionsFieldNumber,
7861 kCustomOptionFieldNumber};
7862 int unint[] = {FileDescriptorProto::kMessageTypeFieldNumber,
7863 1,
7864 DescriptorProto::kExtensionRangeFieldNumber,
7865 1,
7866 DescriptorProto_ExtensionRange::kOptionsFieldNumber,
7867 ExtensionRangeOptions::kUninterpretedOptionFieldNumber,
7868 0};
7869 std::vector<int> vpath(path, path + 6);
7870 EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
7871 EXPECT_EQ("37:41-37:66", PrintSourceLocation(loc));
7872
7873 std::vector<int> vunint(unint, unint + 7);
7874 EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
7875 }
7876
7877 // Field option on extension
7878 {
7879 int path[] = {FileDescriptorProto::kExtensionFieldNumber, 0,
7880 FieldDescriptorProto::kOptionsFieldNumber,
7881 FieldOptions::kPackedFieldNumber};
7882 int unint[] = {FileDescriptorProto::kExtensionFieldNumber, 0,
7883 FieldDescriptorProto::kOptionsFieldNumber,
7884 FieldOptions::kUninterpretedOptionFieldNumber, 0};
7885 std::vector<int> vpath(path, path + 4);
7886 EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
7887 EXPECT_EQ("40:42-40:53", PrintSourceLocation(loc));
7888
7889 std::vector<int> vunint(unint, unint + 5);
7890 EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
7891 }
7892 }
7893
7894 // Missing SourceCodeInfo doesn't cause crash:
TEST_F(SourceLocationTest,GetSourceLocation_MissingSourceCodeInfo)7895 TEST_F(SourceLocationTest, GetSourceLocation_MissingSourceCodeInfo) {
7896 SourceLocation loc;
7897
7898 const FileDescriptor* file_desc =
7899 GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto"));
7900
7901 FileDescriptorProto proto;
7902 file_desc->CopyTo(&proto); // Note, this discards the SourceCodeInfo.
7903 EXPECT_FALSE(proto.has_source_code_info());
7904
7905 DescriptorPool bad1_pool(&pool_);
7906 const FileDescriptor* bad1_file_desc =
7907 GOOGLE_CHECK_NOTNULL(bad1_pool.BuildFile(proto));
7908 const Descriptor* bad1_a_desc = bad1_file_desc->FindMessageTypeByName("A");
7909 EXPECT_FALSE(bad1_a_desc->GetSourceLocation(&loc));
7910 }
7911
7912 // Corrupt SourceCodeInfo doesn't cause crash:
TEST_F(SourceLocationTest,GetSourceLocation_BogusSourceCodeInfo)7913 TEST_F(SourceLocationTest, GetSourceLocation_BogusSourceCodeInfo) {
7914 SourceLocation loc;
7915
7916 const FileDescriptor* file_desc =
7917 GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto"));
7918
7919 FileDescriptorProto proto;
7920 file_desc->CopyTo(&proto); // Note, this discards the SourceCodeInfo.
7921 EXPECT_FALSE(proto.has_source_code_info());
7922 SourceCodeInfo_Location* loc_msg =
7923 proto.mutable_source_code_info()->add_location();
7924 loc_msg->add_path(1);
7925 loc_msg->add_path(2);
7926 loc_msg->add_path(3);
7927 loc_msg->add_span(4);
7928 loc_msg->add_span(5);
7929 loc_msg->add_span(6);
7930
7931 DescriptorPool bad2_pool(&pool_);
7932 const FileDescriptor* bad2_file_desc =
7933 GOOGLE_CHECK_NOTNULL(bad2_pool.BuildFile(proto));
7934 const Descriptor* bad2_a_desc = bad2_file_desc->FindMessageTypeByName("A");
7935 EXPECT_FALSE(bad2_a_desc->GetSourceLocation(&loc));
7936 }
7937
7938 // ===================================================================
7939
7940 const char* const kCopySourceCodeInfoToTestInput =
7941 "syntax = \"proto2\";\n"
7942 "message Foo {}\n";
7943
7944 // Required since source code information is not preserved by
7945 // FileDescriptorTest.
7946 class CopySourceCodeInfoToTest : public testing::Test {
7947 public:
CopySourceCodeInfoToTest()7948 CopySourceCodeInfoToTest()
7949 : source_tree_("/test/test.proto", kCopySourceCodeInfoToTestInput),
7950 db_(&source_tree_),
7951 pool_(&db_, &collector_) {}
7952
7953 private:
7954 AbortingErrorCollector collector_;
7955 SingletonSourceTree source_tree_;
7956 compiler::SourceTreeDescriptorDatabase db_;
7957
7958 protected:
7959 DescriptorPool pool_;
7960 };
7961
TEST_F(CopySourceCodeInfoToTest,CopyTo_DoesNotCopySourceCodeInfo)7962 TEST_F(CopySourceCodeInfoToTest, CopyTo_DoesNotCopySourceCodeInfo) {
7963 const FileDescriptor* file_desc =
7964 GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto"));
7965 FileDescriptorProto file_desc_proto;
7966 ASSERT_FALSE(file_desc_proto.has_source_code_info());
7967
7968 file_desc->CopyTo(&file_desc_proto);
7969 EXPECT_FALSE(file_desc_proto.has_source_code_info());
7970 }
7971
TEST_F(CopySourceCodeInfoToTest,CopySourceCodeInfoTo)7972 TEST_F(CopySourceCodeInfoToTest, CopySourceCodeInfoTo) {
7973 const FileDescriptor* file_desc =
7974 GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto"));
7975 FileDescriptorProto file_desc_proto;
7976 ASSERT_FALSE(file_desc_proto.has_source_code_info());
7977
7978 file_desc->CopySourceCodeInfoTo(&file_desc_proto);
7979 const SourceCodeInfo& info = file_desc_proto.source_code_info();
7980 ASSERT_EQ(4, info.location_size());
7981 // Get the Foo message location
7982 const SourceCodeInfo_Location& foo_location = info.location(2);
7983 ASSERT_EQ(2, foo_location.path_size());
7984 EXPECT_EQ(FileDescriptorProto::kMessageTypeFieldNumber, foo_location.path(0));
7985 EXPECT_EQ(0, foo_location.path(1)); // Foo is the first message defined
7986 ASSERT_EQ(3, foo_location.span_size()); // Foo spans one line
7987 EXPECT_EQ(1, foo_location.span(0)); // Foo is declared on line 1
7988 EXPECT_EQ(0, foo_location.span(1)); // Foo starts at column 0
7989 EXPECT_EQ(14, foo_location.span(2)); // Foo ends on column 14
7990 }
7991
7992 // ===================================================================
7993
7994 class LazilyBuildDependenciesTest : public testing::Test {
7995 public:
LazilyBuildDependenciesTest()7996 LazilyBuildDependenciesTest() : pool_(&db_, nullptr) {
7997 pool_.InternalSetLazilyBuildDependencies();
7998 }
7999
ParseProtoAndAddToDb(const char * proto)8000 void ParseProtoAndAddToDb(const char* proto) {
8001 FileDescriptorProto tmp;
8002 ASSERT_TRUE(TextFormat::ParseFromString(proto, &tmp));
8003 db_.Add(tmp);
8004 }
8005
ParseProtoAndAddToDb(const std::string & proto)8006 void ParseProtoAndAddToDb(const std::string& proto) {
8007 FileDescriptorProto tmp;
8008 ASSERT_TRUE(TextFormat::ParseFromString(proto, &tmp));
8009 db_.Add(tmp);
8010 }
8011
AddSimpleMessageProtoFileToDb(const char * file_name,const char * message_name)8012 void AddSimpleMessageProtoFileToDb(const char* file_name,
8013 const char* message_name) {
8014 ParseProtoAndAddToDb("name: '" + std::string(file_name) +
8015 ".proto' "
8016 "package: \"protobuf_unittest\" "
8017 "message_type { "
8018 " name:'" +
8019 std::string(message_name) +
8020 "' "
8021 " field { name:'a' number:1 "
8022 " label:LABEL_OPTIONAL "
8023 " type_name:'int32' } "
8024 "}");
8025 }
8026
AddSimpleEnumProtoFileToDb(const char * file_name,const char * enum_name,const char * enum_value_name)8027 void AddSimpleEnumProtoFileToDb(const char* file_name, const char* enum_name,
8028 const char* enum_value_name) {
8029 ParseProtoAndAddToDb("name: '" + std::string(file_name) +
8030 ".proto' "
8031 "package: 'protobuf_unittest' "
8032 "enum_type { "
8033 " name:'" +
8034 std::string(enum_name) +
8035 "' "
8036 " value { name:'" +
8037 std::string(enum_value_name) +
8038 "' number:1 } "
8039 "}");
8040 }
8041
8042 protected:
8043 SimpleDescriptorDatabase db_;
8044 DescriptorPool pool_;
8045 };
8046
TEST_F(LazilyBuildDependenciesTest,Message)8047 TEST_F(LazilyBuildDependenciesTest, Message) {
8048 ParseProtoAndAddToDb(
8049 "name: 'foo.proto' "
8050 "package: 'protobuf_unittest' "
8051 "dependency: 'bar.proto' "
8052 "message_type { "
8053 " name:'Foo' "
8054 " field { name:'bar' number:1 label:LABEL_OPTIONAL "
8055 "type_name:'.protobuf_unittest.Bar' } "
8056 "}");
8057 AddSimpleMessageProtoFileToDb("bar", "Bar");
8058
8059 // Verify neither has been built yet.
8060 EXPECT_FALSE(pool_.InternalIsFileLoaded("foo.proto"));
8061 EXPECT_FALSE(pool_.InternalIsFileLoaded("bar.proto"));
8062
8063 const FileDescriptor* file = pool_.FindFileByName("foo.proto");
8064
8065 // Verify only foo gets built when asking for foo.proto
8066 EXPECT_TRUE(file != nullptr);
8067 EXPECT_TRUE(pool_.InternalIsFileLoaded("foo.proto"));
8068 EXPECT_FALSE(pool_.InternalIsFileLoaded("bar.proto"));
8069
8070 // Verify calling FindFieldBy* works when the type of the field was
8071 // not built at cross link time. Verify this doesn't build the file
8072 // the field's type is defined in, as well.
8073 const Descriptor* desc = file->FindMessageTypeByName("Foo");
8074 const FieldDescriptor* field = desc->FindFieldByName("bar");
8075 EXPECT_TRUE(field != nullptr);
8076 EXPECT_EQ(field, desc->FindFieldByNumber(1));
8077 EXPECT_EQ(field, desc->FindFieldByLowercaseName("bar"));
8078 EXPECT_EQ(field, desc->FindFieldByCamelcaseName("bar"));
8079 EXPECT_FALSE(pool_.InternalIsFileLoaded("bar.proto"));
8080
8081 // Finally, verify that if we call message_type() on the field, we will
8082 // build the file where the message is defined, and get a valid descriptor
8083 EXPECT_TRUE(field->message_type() != nullptr);
8084 EXPECT_TRUE(pool_.InternalIsFileLoaded("bar.proto"));
8085 }
8086
TEST_F(LazilyBuildDependenciesTest,Enum)8087 TEST_F(LazilyBuildDependenciesTest, Enum) {
8088 ParseProtoAndAddToDb(
8089 "name: 'foo.proto' "
8090 "package: 'protobuf_unittest' "
8091 "dependency: 'enum1.proto' "
8092 "dependency: 'enum2.proto' "
8093 "message_type { "
8094 " name:'Lazy' "
8095 " field { name:'enum1' number:1 label:LABEL_OPTIONAL "
8096 "type_name:'.protobuf_unittest.Enum1' } "
8097 " field { name:'enum2' number:1 label:LABEL_OPTIONAL "
8098 "type_name:'.protobuf_unittest.Enum2' } "
8099 "}");
8100 AddSimpleEnumProtoFileToDb("enum1", "Enum1", "ENUM1");
8101 AddSimpleEnumProtoFileToDb("enum2", "Enum2", "ENUM2");
8102
8103 const FileDescriptor* file = pool_.FindFileByName("foo.proto");
8104
8105 // Verify calling enum_type() on a field whose definition is not
8106 // yet built will build the file and return a descriptor.
8107 EXPECT_FALSE(pool_.InternalIsFileLoaded("enum1.proto"));
8108 const Descriptor* desc = file->FindMessageTypeByName("Lazy");
8109 EXPECT_TRUE(desc != nullptr);
8110 const FieldDescriptor* field = desc->FindFieldByName("enum1");
8111 EXPECT_TRUE(field != nullptr);
8112 EXPECT_TRUE(field->enum_type() != nullptr);
8113 EXPECT_TRUE(pool_.InternalIsFileLoaded("enum1.proto"));
8114
8115 // Verify calling default_value_enum() on a field whose definition is not
8116 // yet built will build the file and return a descriptor to the value.
8117 EXPECT_FALSE(pool_.InternalIsFileLoaded("enum2.proto"));
8118 field = desc->FindFieldByName("enum2");
8119 EXPECT_TRUE(field != nullptr);
8120 EXPECT_TRUE(field->default_value_enum() != nullptr);
8121 EXPECT_TRUE(pool_.InternalIsFileLoaded("enum2.proto"));
8122 }
8123
TEST_F(LazilyBuildDependenciesTest,Type)8124 TEST_F(LazilyBuildDependenciesTest, Type) {
8125 ParseProtoAndAddToDb(
8126 "name: 'foo.proto' "
8127 "package: 'protobuf_unittest' "
8128 "dependency: 'message1.proto' "
8129 "dependency: 'message2.proto' "
8130 "dependency: 'enum1.proto' "
8131 "dependency: 'enum2.proto' "
8132 "message_type { "
8133 " name:'Lazy' "
8134 " field { name:'message1' number:1 label:LABEL_OPTIONAL "
8135 "type_name:'.protobuf_unittest.Message1' } "
8136 " field { name:'message2' number:1 label:LABEL_OPTIONAL "
8137 "type_name:'.protobuf_unittest.Message2' } "
8138 " field { name:'enum1' number:1 label:LABEL_OPTIONAL "
8139 "type_name:'.protobuf_unittest.Enum1' } "
8140 " field { name:'enum2' number:1 label:LABEL_OPTIONAL "
8141 "type_name:'.protobuf_unittest.Enum2' } "
8142 "}");
8143 AddSimpleMessageProtoFileToDb("message1", "Message1");
8144 AddSimpleMessageProtoFileToDb("message2", "Message2");
8145 AddSimpleEnumProtoFileToDb("enum1", "Enum1", "ENUM1");
8146 AddSimpleEnumProtoFileToDb("enum2", "Enum2", "ENUM2");
8147
8148 const FileDescriptor* file = pool_.FindFileByName("foo.proto");
8149
8150 // Verify calling type() on a field that is a message type will
8151 // build the type defined in another file.
8152 EXPECT_FALSE(pool_.InternalIsFileLoaded("message1.proto"));
8153 const Descriptor* desc = file->FindMessageTypeByName("Lazy");
8154 EXPECT_TRUE(desc != nullptr);
8155 const FieldDescriptor* field = desc->FindFieldByName("message1");
8156 EXPECT_TRUE(field != nullptr);
8157 EXPECT_EQ(field->type(), FieldDescriptor::TYPE_MESSAGE);
8158 EXPECT_TRUE(pool_.InternalIsFileLoaded("message1.proto"));
8159
8160 // Verify calling cpp_type() on a field that is a message type will
8161 // build the type defined in another file.
8162 EXPECT_FALSE(pool_.InternalIsFileLoaded("message2.proto"));
8163 field = desc->FindFieldByName("message2");
8164 EXPECT_TRUE(field != nullptr);
8165 EXPECT_EQ(field->cpp_type(), FieldDescriptor::CPPTYPE_MESSAGE);
8166 EXPECT_TRUE(pool_.InternalIsFileLoaded("message2.proto"));
8167
8168 // Verify calling type() on a field that is an enum type will
8169 // build the type defined in another file.
8170 EXPECT_FALSE(pool_.InternalIsFileLoaded("enum1.proto"));
8171 field = desc->FindFieldByName("enum1");
8172 EXPECT_TRUE(field != nullptr);
8173 EXPECT_EQ(field->type(), FieldDescriptor::TYPE_ENUM);
8174 EXPECT_TRUE(pool_.InternalIsFileLoaded("enum1.proto"));
8175
8176 // Verify calling cpp_type() on a field that is an enum type will
8177 // build the type defined in another file.
8178 EXPECT_FALSE(pool_.InternalIsFileLoaded("enum2.proto"));
8179 field = desc->FindFieldByName("enum2");
8180 EXPECT_TRUE(field != nullptr);
8181 EXPECT_EQ(field->cpp_type(), FieldDescriptor::CPPTYPE_ENUM);
8182 EXPECT_TRUE(pool_.InternalIsFileLoaded("enum2.proto"));
8183 }
8184
TEST_F(LazilyBuildDependenciesTest,Extension)8185 TEST_F(LazilyBuildDependenciesTest, Extension) {
8186 ParseProtoAndAddToDb(
8187 "name: 'foo.proto' "
8188 "package: 'protobuf_unittest' "
8189 "dependency: 'bar.proto' "
8190 "dependency: 'baz.proto' "
8191 "extension { extendee: '.protobuf_unittest.Bar' name:'bar' number:11"
8192 " label:LABEL_OPTIONAL type_name:'.protobuf_unittest.Baz' }");
8193 ParseProtoAndAddToDb(
8194 "name: 'bar.proto' "
8195 "package: 'protobuf_unittest' "
8196 "message_type { "
8197 " name:'Bar' "
8198 " extension_range { start: 10 end: 20 }"
8199 "}");
8200 AddSimpleMessageProtoFileToDb("baz", "Baz");
8201
8202 // Verify none have been built yet.
8203 EXPECT_FALSE(pool_.InternalIsFileLoaded("foo.proto"));
8204 EXPECT_FALSE(pool_.InternalIsFileLoaded("bar.proto"));
8205 EXPECT_FALSE(pool_.InternalIsFileLoaded("baz.proto"));
8206
8207 const FileDescriptor* file = pool_.FindFileByName("foo.proto");
8208
8209 // Verify foo.bar gets loaded, and bar.proto gets loaded
8210 // to register the extension. baz.proto should not get loaded.
8211 EXPECT_TRUE(file != nullptr);
8212 EXPECT_TRUE(pool_.InternalIsFileLoaded("foo.proto"));
8213 EXPECT_TRUE(pool_.InternalIsFileLoaded("bar.proto"));
8214 EXPECT_FALSE(pool_.InternalIsFileLoaded("baz.proto"));
8215 }
8216
TEST_F(LazilyBuildDependenciesTest,Service)8217 TEST_F(LazilyBuildDependenciesTest, Service) {
8218 ParseProtoAndAddToDb(
8219 "name: 'foo.proto' "
8220 "package: 'protobuf_unittest' "
8221 "dependency: 'message1.proto' "
8222 "dependency: 'message2.proto' "
8223 "dependency: 'message3.proto' "
8224 "dependency: 'message4.proto' "
8225 "service {"
8226 " name: 'LazyService'"
8227 " method { name: 'A' input_type: '.protobuf_unittest.Message1' "
8228 " output_type: '.protobuf_unittest.Message2' }"
8229 "}");
8230 AddSimpleMessageProtoFileToDb("message1", "Message1");
8231 AddSimpleMessageProtoFileToDb("message2", "Message2");
8232 AddSimpleMessageProtoFileToDb("message3", "Message3");
8233 AddSimpleMessageProtoFileToDb("message4", "Message4");
8234
8235 const FileDescriptor* file = pool_.FindFileByName("foo.proto");
8236
8237 // Verify calling FindServiceByName or FindMethodByName doesn't build the
8238 // files defining the input and output type, and input_type() and
8239 // output_type() does indeed build the appropriate files.
8240 const ServiceDescriptor* service = file->FindServiceByName("LazyService");
8241 EXPECT_TRUE(service != nullptr);
8242 const MethodDescriptor* method = service->FindMethodByName("A");
8243 EXPECT_FALSE(pool_.InternalIsFileLoaded("message1.proto"));
8244 EXPECT_FALSE(pool_.InternalIsFileLoaded("message2.proto"));
8245 EXPECT_TRUE(method != nullptr);
8246 EXPECT_TRUE(method->input_type() != nullptr);
8247 EXPECT_TRUE(pool_.InternalIsFileLoaded("message1.proto"));
8248 EXPECT_FALSE(pool_.InternalIsFileLoaded("message2.proto"));
8249 EXPECT_TRUE(method->output_type() != nullptr);
8250 EXPECT_TRUE(pool_.InternalIsFileLoaded("message2.proto"));
8251 }
8252
8253
TEST_F(LazilyBuildDependenciesTest,GeneratedFile)8254 TEST_F(LazilyBuildDependenciesTest, GeneratedFile) {
8255 // Most testing is done with custom pools with lazy dependencies forced on,
8256 // do some sanity checking that lazy imports is on by default for the
8257 // generated pool, and do custom options testing with generated to
8258 // be able to use the GetExtension ids for the custom options.
8259
8260 // Verify none of the files are loaded yet.
8261 EXPECT_FALSE(DescriptorPool::generated_pool()->InternalIsFileLoaded(
8262 "google/protobuf/unittest_lazy_dependencies.proto"));
8263 EXPECT_FALSE(DescriptorPool::generated_pool()->InternalIsFileLoaded(
8264 "google/protobuf/unittest_lazy_dependencies_custom_option.proto"));
8265 EXPECT_FALSE(DescriptorPool::generated_pool()->InternalIsFileLoaded(
8266 "google/protobuf/unittest_lazy_dependencies_enum.proto"));
8267
8268 // Verify calling autogenerated function to get a descriptor in the base
8269 // file will build that file but none of it's imports. This verifies that
8270 // lazily_build_dependencies_ is set on the generated pool, and also that
8271 // the generated function "descriptor()" doesn't somehow subvert the laziness
8272 // by manually loading the dependencies or something.
8273 EXPECT_TRUE(protobuf_unittest::lazy_imports::ImportedMessage::descriptor() !=
8274 nullptr);
8275 EXPECT_TRUE(DescriptorPool::generated_pool()->InternalIsFileLoaded(
8276 "google/protobuf/unittest_lazy_dependencies.proto"));
8277 EXPECT_FALSE(DescriptorPool::generated_pool()->InternalIsFileLoaded(
8278 "google/protobuf/unittest_lazy_dependencies_custom_option.proto"));
8279 EXPECT_FALSE(DescriptorPool::generated_pool()->InternalIsFileLoaded(
8280 "google/protobuf/unittest_lazy_dependencies_enum.proto"));
8281
8282 // Verify custom options work when defined in an import that isn't loaded,
8283 // and that a non-default value of a custom option doesn't load the file
8284 // where that enum is defined.
8285 const MessageOptions& options =
8286 protobuf_unittest::lazy_imports::MessageCustomOption::descriptor()
8287 ->options();
8288 protobuf_unittest::lazy_imports::LazyEnum custom_option_value =
8289 options.GetExtension(protobuf_unittest::lazy_imports::lazy_enum_option);
8290
8291 EXPECT_FALSE(DescriptorPool::generated_pool()->InternalIsFileLoaded(
8292 "google/protobuf/unittest_lazy_dependencies_custom_option.proto"));
8293 EXPECT_FALSE(DescriptorPool::generated_pool()->InternalIsFileLoaded(
8294 "google/protobuf/unittest_lazy_dependencies_enum.proto"));
8295 EXPECT_EQ(custom_option_value, protobuf_unittest::lazy_imports::LAZY_ENUM_1);
8296
8297 const MessageOptions& options2 =
8298 protobuf_unittest::lazy_imports::MessageCustomOption2::descriptor()
8299 ->options();
8300 custom_option_value =
8301 options2.GetExtension(protobuf_unittest::lazy_imports::lazy_enum_option);
8302
8303 EXPECT_FALSE(DescriptorPool::generated_pool()->InternalIsFileLoaded(
8304 "google/protobuf/unittest_lazy_dependencies_custom_option.proto"));
8305 EXPECT_FALSE(DescriptorPool::generated_pool()->InternalIsFileLoaded(
8306 "google/protobuf/unittest_lazy_dependencies_enum.proto"));
8307 EXPECT_EQ(custom_option_value, protobuf_unittest::lazy_imports::LAZY_ENUM_0);
8308 }
8309
TEST_F(LazilyBuildDependenciesTest,Dependency)8310 TEST_F(LazilyBuildDependenciesTest, Dependency) {
8311 ParseProtoAndAddToDb(
8312 "name: 'foo.proto' "
8313 "package: 'protobuf_unittest' "
8314 "dependency: 'bar.proto' "
8315 "message_type { "
8316 " name:'Foo' "
8317 " field { name:'bar' number:1 label:LABEL_OPTIONAL "
8318 "type_name:'.protobuf_unittest.Bar' } "
8319 "}");
8320 ParseProtoAndAddToDb(
8321 "name: 'bar.proto' "
8322 "package: 'protobuf_unittest' "
8323 "dependency: 'baz.proto' "
8324 "message_type { "
8325 " name:'Bar' "
8326 " field { name:'baz' number:1 label:LABEL_OPTIONAL "
8327 "type_name:'.protobuf_unittest.Baz' } "
8328 "}");
8329 AddSimpleMessageProtoFileToDb("baz", "Baz");
8330
8331 const FileDescriptor* foo_file = pool_.FindFileByName("foo.proto");
8332 EXPECT_TRUE(foo_file != nullptr);
8333 // As expected, requesting foo.proto shouldn't build it's dependencies
8334 EXPECT_TRUE(pool_.InternalIsFileLoaded("foo.proto"));
8335 EXPECT_FALSE(pool_.InternalIsFileLoaded("bar.proto"));
8336 EXPECT_FALSE(pool_.InternalIsFileLoaded("baz.proto"));
8337
8338 // Verify calling dependency(N) will build the dependency, but
8339 // not that file's dependencies.
8340 const FileDescriptor* bar_file = foo_file->dependency(0);
8341 EXPECT_TRUE(bar_file != nullptr);
8342 EXPECT_TRUE(pool_.InternalIsFileLoaded("bar.proto"));
8343 EXPECT_FALSE(pool_.InternalIsFileLoaded("baz.proto"));
8344 }
8345
8346 // ===================================================================
8347
8348
8349 } // namespace descriptor_unittest
8350 } // namespace protobuf
8351 } // namespace google
8352
8353 #include <google/protobuf/port_undef.inc>
8354