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