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