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