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