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