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