1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 // http://code.google.com/p/protobuf/
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 class StylizedFieldNamesTest : public testing::Test {
650 protected:
SetUp()651 void SetUp() {
652 FileDescriptorProto file;
653 file.set_name("foo.proto");
654
655 AddExtensionRange(AddMessage(&file, "ExtendableMessage"), 1, 1000);
656
657 DescriptorProto* message = AddMessage(&file, "TestMessage");
658 AddField(message, "foo_foo", 1,
659 FieldDescriptorProto::LABEL_OPTIONAL,
660 FieldDescriptorProto::TYPE_INT32);
661 AddField(message, "FooBar", 2,
662 FieldDescriptorProto::LABEL_OPTIONAL,
663 FieldDescriptorProto::TYPE_INT32);
664 AddField(message, "fooBaz", 3,
665 FieldDescriptorProto::LABEL_OPTIONAL,
666 FieldDescriptorProto::TYPE_INT32);
667 AddField(message, "fooFoo", 4, // Camel-case conflict with foo_foo.
668 FieldDescriptorProto::LABEL_OPTIONAL,
669 FieldDescriptorProto::TYPE_INT32);
670 AddField(message, "foobar", 5, // Lower-case conflict with FooBar.
671 FieldDescriptorProto::LABEL_OPTIONAL,
672 FieldDescriptorProto::TYPE_INT32);
673
674 AddNestedExtension(message, "ExtendableMessage", "bar_foo", 1,
675 FieldDescriptorProto::LABEL_OPTIONAL,
676 FieldDescriptorProto::TYPE_INT32);
677 AddNestedExtension(message, "ExtendableMessage", "BarBar", 2,
678 FieldDescriptorProto::LABEL_OPTIONAL,
679 FieldDescriptorProto::TYPE_INT32);
680 AddNestedExtension(message, "ExtendableMessage", "BarBaz", 3,
681 FieldDescriptorProto::LABEL_OPTIONAL,
682 FieldDescriptorProto::TYPE_INT32);
683 AddNestedExtension(message, "ExtendableMessage", "barFoo", 4, // Conflict
684 FieldDescriptorProto::LABEL_OPTIONAL,
685 FieldDescriptorProto::TYPE_INT32);
686 AddNestedExtension(message, "ExtendableMessage", "barbar", 5, // Conflict
687 FieldDescriptorProto::LABEL_OPTIONAL,
688 FieldDescriptorProto::TYPE_INT32);
689
690 AddExtension(&file, "ExtendableMessage", "baz_foo", 11,
691 FieldDescriptorProto::LABEL_OPTIONAL,
692 FieldDescriptorProto::TYPE_INT32);
693 AddExtension(&file, "ExtendableMessage", "BazBar", 12,
694 FieldDescriptorProto::LABEL_OPTIONAL,
695 FieldDescriptorProto::TYPE_INT32);
696 AddExtension(&file, "ExtendableMessage", "BazBaz", 13,
697 FieldDescriptorProto::LABEL_OPTIONAL,
698 FieldDescriptorProto::TYPE_INT32);
699 AddExtension(&file, "ExtendableMessage", "bazFoo", 14, // Conflict
700 FieldDescriptorProto::LABEL_OPTIONAL,
701 FieldDescriptorProto::TYPE_INT32);
702 AddExtension(&file, "ExtendableMessage", "bazbar", 15, // Conflict
703 FieldDescriptorProto::LABEL_OPTIONAL,
704 FieldDescriptorProto::TYPE_INT32);
705
706 file_ = pool_.BuildFile(file);
707 ASSERT_TRUE(file_ != NULL);
708 ASSERT_EQ(2, file_->message_type_count());
709 message_ = file_->message_type(1);
710 ASSERT_EQ("TestMessage", message_->name());
711 ASSERT_EQ(5, message_->field_count());
712 ASSERT_EQ(5, message_->extension_count());
713 ASSERT_EQ(5, file_->extension_count());
714 }
715
716 DescriptorPool pool_;
717 const FileDescriptor* file_;
718 const Descriptor* message_;
719 };
720
TEST_F(StylizedFieldNamesTest,LowercaseName)721 TEST_F(StylizedFieldNamesTest, LowercaseName) {
722 EXPECT_EQ("foo_foo", message_->field(0)->lowercase_name());
723 EXPECT_EQ("foobar" , message_->field(1)->lowercase_name());
724 EXPECT_EQ("foobaz" , message_->field(2)->lowercase_name());
725 EXPECT_EQ("foofoo" , message_->field(3)->lowercase_name());
726 EXPECT_EQ("foobar" , message_->field(4)->lowercase_name());
727
728 EXPECT_EQ("bar_foo", message_->extension(0)->lowercase_name());
729 EXPECT_EQ("barbar" , message_->extension(1)->lowercase_name());
730 EXPECT_EQ("barbaz" , message_->extension(2)->lowercase_name());
731 EXPECT_EQ("barfoo" , message_->extension(3)->lowercase_name());
732 EXPECT_EQ("barbar" , message_->extension(4)->lowercase_name());
733
734 EXPECT_EQ("baz_foo", file_->extension(0)->lowercase_name());
735 EXPECT_EQ("bazbar" , file_->extension(1)->lowercase_name());
736 EXPECT_EQ("bazbaz" , file_->extension(2)->lowercase_name());
737 EXPECT_EQ("bazfoo" , file_->extension(3)->lowercase_name());
738 EXPECT_EQ("bazbar" , file_->extension(4)->lowercase_name());
739 }
740
TEST_F(StylizedFieldNamesTest,CamelcaseName)741 TEST_F(StylizedFieldNamesTest, CamelcaseName) {
742 EXPECT_EQ("fooFoo", message_->field(0)->camelcase_name());
743 EXPECT_EQ("fooBar", message_->field(1)->camelcase_name());
744 EXPECT_EQ("fooBaz", message_->field(2)->camelcase_name());
745 EXPECT_EQ("fooFoo", message_->field(3)->camelcase_name());
746 EXPECT_EQ("foobar", message_->field(4)->camelcase_name());
747
748 EXPECT_EQ("barFoo", message_->extension(0)->camelcase_name());
749 EXPECT_EQ("barBar", message_->extension(1)->camelcase_name());
750 EXPECT_EQ("barBaz", message_->extension(2)->camelcase_name());
751 EXPECT_EQ("barFoo", message_->extension(3)->camelcase_name());
752 EXPECT_EQ("barbar", message_->extension(4)->camelcase_name());
753
754 EXPECT_EQ("bazFoo", file_->extension(0)->camelcase_name());
755 EXPECT_EQ("bazBar", file_->extension(1)->camelcase_name());
756 EXPECT_EQ("bazBaz", file_->extension(2)->camelcase_name());
757 EXPECT_EQ("bazFoo", file_->extension(3)->camelcase_name());
758 EXPECT_EQ("bazbar", file_->extension(4)->camelcase_name());
759 }
760
TEST_F(StylizedFieldNamesTest,FindByLowercaseName)761 TEST_F(StylizedFieldNamesTest, FindByLowercaseName) {
762 EXPECT_EQ(message_->field(0),
763 message_->FindFieldByLowercaseName("foo_foo"));
764 EXPECT_EQ(message_->field(1),
765 message_->FindFieldByLowercaseName("foobar"));
766 EXPECT_EQ(message_->field(2),
767 message_->FindFieldByLowercaseName("foobaz"));
768 EXPECT_TRUE(message_->FindFieldByLowercaseName("FooBar") == NULL);
769 EXPECT_TRUE(message_->FindFieldByLowercaseName("fooBaz") == NULL);
770 EXPECT_TRUE(message_->FindFieldByLowercaseName("bar_foo") == NULL);
771 EXPECT_TRUE(message_->FindFieldByLowercaseName("nosuchfield") == NULL);
772
773 EXPECT_EQ(message_->extension(0),
774 message_->FindExtensionByLowercaseName("bar_foo"));
775 EXPECT_EQ(message_->extension(1),
776 message_->FindExtensionByLowercaseName("barbar"));
777 EXPECT_EQ(message_->extension(2),
778 message_->FindExtensionByLowercaseName("barbaz"));
779 EXPECT_TRUE(message_->FindExtensionByLowercaseName("BarBar") == NULL);
780 EXPECT_TRUE(message_->FindExtensionByLowercaseName("barBaz") == NULL);
781 EXPECT_TRUE(message_->FindExtensionByLowercaseName("foo_foo") == NULL);
782 EXPECT_TRUE(message_->FindExtensionByLowercaseName("nosuchfield") == NULL);
783
784 EXPECT_EQ(file_->extension(0),
785 file_->FindExtensionByLowercaseName("baz_foo"));
786 EXPECT_EQ(file_->extension(1),
787 file_->FindExtensionByLowercaseName("bazbar"));
788 EXPECT_EQ(file_->extension(2),
789 file_->FindExtensionByLowercaseName("bazbaz"));
790 EXPECT_TRUE(file_->FindExtensionByLowercaseName("BazBar") == NULL);
791 EXPECT_TRUE(file_->FindExtensionByLowercaseName("bazBaz") == NULL);
792 EXPECT_TRUE(file_->FindExtensionByLowercaseName("nosuchfield") == NULL);
793 }
794
TEST_F(StylizedFieldNamesTest,FindByCamelcaseName)795 TEST_F(StylizedFieldNamesTest, FindByCamelcaseName) {
796 EXPECT_EQ(message_->field(0),
797 message_->FindFieldByCamelcaseName("fooFoo"));
798 EXPECT_EQ(message_->field(1),
799 message_->FindFieldByCamelcaseName("fooBar"));
800 EXPECT_EQ(message_->field(2),
801 message_->FindFieldByCamelcaseName("fooBaz"));
802 EXPECT_TRUE(message_->FindFieldByCamelcaseName("foo_foo") == NULL);
803 EXPECT_TRUE(message_->FindFieldByCamelcaseName("FooBar") == NULL);
804 EXPECT_TRUE(message_->FindFieldByCamelcaseName("barFoo") == NULL);
805 EXPECT_TRUE(message_->FindFieldByCamelcaseName("nosuchfield") == NULL);
806
807 EXPECT_EQ(message_->extension(0),
808 message_->FindExtensionByCamelcaseName("barFoo"));
809 EXPECT_EQ(message_->extension(1),
810 message_->FindExtensionByCamelcaseName("barBar"));
811 EXPECT_EQ(message_->extension(2),
812 message_->FindExtensionByCamelcaseName("barBaz"));
813 EXPECT_TRUE(message_->FindExtensionByCamelcaseName("bar_foo") == NULL);
814 EXPECT_TRUE(message_->FindExtensionByCamelcaseName("BarBar") == NULL);
815 EXPECT_TRUE(message_->FindExtensionByCamelcaseName("fooFoo") == NULL);
816 EXPECT_TRUE(message_->FindExtensionByCamelcaseName("nosuchfield") == NULL);
817
818 EXPECT_EQ(file_->extension(0),
819 file_->FindExtensionByCamelcaseName("bazFoo"));
820 EXPECT_EQ(file_->extension(1),
821 file_->FindExtensionByCamelcaseName("bazBar"));
822 EXPECT_EQ(file_->extension(2),
823 file_->FindExtensionByCamelcaseName("bazBaz"));
824 EXPECT_TRUE(file_->FindExtensionByCamelcaseName("baz_foo") == NULL);
825 EXPECT_TRUE(file_->FindExtensionByCamelcaseName("BazBar") == NULL);
826 EXPECT_TRUE(file_->FindExtensionByCamelcaseName("nosuchfield") == NULL);
827 }
828
829 // ===================================================================
830
831 // Test enum descriptors.
832 class EnumDescriptorTest : public testing::Test {
833 protected:
SetUp()834 virtual void SetUp() {
835 // Build descriptors for the following definitions:
836 //
837 // // in "foo.proto"
838 // enum TestEnum {
839 // FOO = 1;
840 // BAR = 2;
841 // }
842 //
843 // // in "bar.proto"
844 // package corge.grault;
845 // enum TestEnum2 {
846 // FOO = 1;
847 // BAZ = 3;
848 // }
849 //
850 // TestEnum2 is primarily here to test FindValueByName and friends.
851 // All enums created from the same DescriptorPool share the same lookup
852 // table, so we need to insure that they don't interfere.
853
854 // TestEnum
855 FileDescriptorProto foo_file;
856 foo_file.set_name("foo.proto");
857
858 EnumDescriptorProto* enum_proto = AddEnum(&foo_file, "TestEnum");
859 AddEnumValue(enum_proto, "FOO", 1);
860 AddEnumValue(enum_proto, "BAR", 2);
861
862 // TestEnum2
863 FileDescriptorProto bar_file;
864 bar_file.set_name("bar.proto");
865 bar_file.set_package("corge.grault");
866
867 EnumDescriptorProto* enum2_proto = AddEnum(&bar_file, "TestEnum2");
868 AddEnumValue(enum2_proto, "FOO", 1);
869 AddEnumValue(enum2_proto, "BAZ", 3);
870
871 // Build the descriptors and get the pointers.
872 foo_file_ = pool_.BuildFile(foo_file);
873 ASSERT_TRUE(foo_file_ != NULL);
874
875 bar_file_ = pool_.BuildFile(bar_file);
876 ASSERT_TRUE(bar_file_ != NULL);
877
878 ASSERT_EQ(1, foo_file_->enum_type_count());
879 enum_ = foo_file_->enum_type(0);
880
881 ASSERT_EQ(2, enum_->value_count());
882 foo_ = enum_->value(0);
883 bar_ = enum_->value(1);
884
885 ASSERT_EQ(1, bar_file_->enum_type_count());
886 enum2_ = bar_file_->enum_type(0);
887
888 ASSERT_EQ(2, enum2_->value_count());
889 foo2_ = enum2_->value(0);
890 baz2_ = enum2_->value(1);
891 }
892
893 DescriptorPool pool_;
894
895 const FileDescriptor* foo_file_;
896 const FileDescriptor* bar_file_;
897
898 const EnumDescriptor* enum_;
899 const EnumDescriptor* enum2_;
900
901 const EnumValueDescriptor* foo_;
902 const EnumValueDescriptor* bar_;
903
904 const EnumValueDescriptor* foo2_;
905 const EnumValueDescriptor* baz2_;
906 };
907
TEST_F(EnumDescriptorTest,Name)908 TEST_F(EnumDescriptorTest, Name) {
909 EXPECT_EQ("TestEnum", enum_->name());
910 EXPECT_EQ("TestEnum", enum_->full_name());
911 EXPECT_EQ(foo_file_, enum_->file());
912
913 EXPECT_EQ("TestEnum2", enum2_->name());
914 EXPECT_EQ("corge.grault.TestEnum2", enum2_->full_name());
915 EXPECT_EQ(bar_file_, enum2_->file());
916 }
917
TEST_F(EnumDescriptorTest,ContainingType)918 TEST_F(EnumDescriptorTest, ContainingType) {
919 EXPECT_TRUE(enum_->containing_type() == NULL);
920 EXPECT_TRUE(enum2_->containing_type() == NULL);
921 }
922
TEST_F(EnumDescriptorTest,ValuesByIndex)923 TEST_F(EnumDescriptorTest, ValuesByIndex) {
924 ASSERT_EQ(2, enum_->value_count());
925 EXPECT_EQ(foo_, enum_->value(0));
926 EXPECT_EQ(bar_, enum_->value(1));
927 }
928
TEST_F(EnumDescriptorTest,FindValueByName)929 TEST_F(EnumDescriptorTest, FindValueByName) {
930 EXPECT_EQ(foo_ , enum_ ->FindValueByName("FOO"));
931 EXPECT_EQ(bar_ , enum_ ->FindValueByName("BAR"));
932 EXPECT_EQ(foo2_, enum2_->FindValueByName("FOO"));
933 EXPECT_EQ(baz2_, enum2_->FindValueByName("BAZ"));
934
935 EXPECT_TRUE(enum_ ->FindValueByName("NO_SUCH_VALUE") == NULL);
936 EXPECT_TRUE(enum_ ->FindValueByName("BAZ" ) == NULL);
937 EXPECT_TRUE(enum2_->FindValueByName("BAR" ) == NULL);
938 }
939
TEST_F(EnumDescriptorTest,FindValueByNumber)940 TEST_F(EnumDescriptorTest, FindValueByNumber) {
941 EXPECT_EQ(foo_ , enum_ ->FindValueByNumber(1));
942 EXPECT_EQ(bar_ , enum_ ->FindValueByNumber(2));
943 EXPECT_EQ(foo2_, enum2_->FindValueByNumber(1));
944 EXPECT_EQ(baz2_, enum2_->FindValueByNumber(3));
945
946 EXPECT_TRUE(enum_ ->FindValueByNumber(416) == NULL);
947 EXPECT_TRUE(enum_ ->FindValueByNumber(3) == NULL);
948 EXPECT_TRUE(enum2_->FindValueByNumber(2) == NULL);
949 }
950
TEST_F(EnumDescriptorTest,ValueName)951 TEST_F(EnumDescriptorTest, ValueName) {
952 EXPECT_EQ("FOO", foo_->name());
953 EXPECT_EQ("BAR", bar_->name());
954 }
955
TEST_F(EnumDescriptorTest,ValueFullName)956 TEST_F(EnumDescriptorTest, ValueFullName) {
957 EXPECT_EQ("FOO", foo_->full_name());
958 EXPECT_EQ("BAR", bar_->full_name());
959 EXPECT_EQ("corge.grault.FOO", foo2_->full_name());
960 EXPECT_EQ("corge.grault.BAZ", baz2_->full_name());
961 }
962
TEST_F(EnumDescriptorTest,ValueIndex)963 TEST_F(EnumDescriptorTest, ValueIndex) {
964 EXPECT_EQ(0, foo_->index());
965 EXPECT_EQ(1, bar_->index());
966 }
967
TEST_F(EnumDescriptorTest,ValueNumber)968 TEST_F(EnumDescriptorTest, ValueNumber) {
969 EXPECT_EQ(1, foo_->number());
970 EXPECT_EQ(2, bar_->number());
971 }
972
TEST_F(EnumDescriptorTest,ValueType)973 TEST_F(EnumDescriptorTest, ValueType) {
974 EXPECT_EQ(enum_ , foo_ ->type());
975 EXPECT_EQ(enum_ , bar_ ->type());
976 EXPECT_EQ(enum2_, foo2_->type());
977 EXPECT_EQ(enum2_, baz2_->type());
978 }
979
980 // ===================================================================
981
982 // Test service descriptors.
983 class ServiceDescriptorTest : public testing::Test {
984 protected:
SetUp()985 virtual void SetUp() {
986 // Build descriptors for the following messages and service:
987 // // in "foo.proto"
988 // message FooRequest {}
989 // message FooResponse {}
990 // message BarRequest {}
991 // message BarResponse {}
992 // message BazRequest {}
993 // message BazResponse {}
994 //
995 // service TestService {
996 // rpc Foo(FooRequest) returns (FooResponse);
997 // rpc Bar(BarRequest) returns (BarResponse);
998 // }
999 //
1000 // // in "bar.proto"
1001 // package corge.grault
1002 // service TestService2 {
1003 // rpc Foo(FooRequest) returns (FooResponse);
1004 // rpc Baz(BazRequest) returns (BazResponse);
1005 // }
1006
1007 FileDescriptorProto foo_file;
1008 foo_file.set_name("foo.proto");
1009
1010 AddMessage(&foo_file, "FooRequest");
1011 AddMessage(&foo_file, "FooResponse");
1012 AddMessage(&foo_file, "BarRequest");
1013 AddMessage(&foo_file, "BarResponse");
1014 AddMessage(&foo_file, "BazRequest");
1015 AddMessage(&foo_file, "BazResponse");
1016
1017 ServiceDescriptorProto* service = AddService(&foo_file, "TestService");
1018 AddMethod(service, "Foo", "FooRequest", "FooResponse");
1019 AddMethod(service, "Bar", "BarRequest", "BarResponse");
1020
1021 FileDescriptorProto bar_file;
1022 bar_file.set_name("bar.proto");
1023 bar_file.set_package("corge.grault");
1024 bar_file.add_dependency("foo.proto");
1025
1026 ServiceDescriptorProto* service2 = AddService(&bar_file, "TestService2");
1027 AddMethod(service2, "Foo", "FooRequest", "FooResponse");
1028 AddMethod(service2, "Baz", "BazRequest", "BazResponse");
1029
1030 // Build the descriptors and get the pointers.
1031 foo_file_ = pool_.BuildFile(foo_file);
1032 ASSERT_TRUE(foo_file_ != NULL);
1033
1034 bar_file_ = pool_.BuildFile(bar_file);
1035 ASSERT_TRUE(bar_file_ != NULL);
1036
1037 ASSERT_EQ(6, foo_file_->message_type_count());
1038 foo_request_ = foo_file_->message_type(0);
1039 foo_response_ = foo_file_->message_type(1);
1040 bar_request_ = foo_file_->message_type(2);
1041 bar_response_ = foo_file_->message_type(3);
1042 baz_request_ = foo_file_->message_type(4);
1043 baz_response_ = foo_file_->message_type(5);
1044
1045 ASSERT_EQ(1, foo_file_->service_count());
1046 service_ = foo_file_->service(0);
1047
1048 ASSERT_EQ(2, service_->method_count());
1049 foo_ = service_->method(0);
1050 bar_ = service_->method(1);
1051
1052 ASSERT_EQ(1, bar_file_->service_count());
1053 service2_ = bar_file_->service(0);
1054
1055 ASSERT_EQ(2, service2_->method_count());
1056 foo2_ = service2_->method(0);
1057 baz2_ = service2_->method(1);
1058 }
1059
1060 DescriptorPool pool_;
1061
1062 const FileDescriptor* foo_file_;
1063 const FileDescriptor* bar_file_;
1064
1065 const Descriptor* foo_request_;
1066 const Descriptor* foo_response_;
1067 const Descriptor* bar_request_;
1068 const Descriptor* bar_response_;
1069 const Descriptor* baz_request_;
1070 const Descriptor* baz_response_;
1071
1072 const ServiceDescriptor* service_;
1073 const ServiceDescriptor* service2_;
1074
1075 const MethodDescriptor* foo_;
1076 const MethodDescriptor* bar_;
1077
1078 const MethodDescriptor* foo2_;
1079 const MethodDescriptor* baz2_;
1080 };
1081
TEST_F(ServiceDescriptorTest,Name)1082 TEST_F(ServiceDescriptorTest, Name) {
1083 EXPECT_EQ("TestService", service_->name());
1084 EXPECT_EQ("TestService", service_->full_name());
1085 EXPECT_EQ(foo_file_, service_->file());
1086
1087 EXPECT_EQ("TestService2", service2_->name());
1088 EXPECT_EQ("corge.grault.TestService2", service2_->full_name());
1089 EXPECT_EQ(bar_file_, service2_->file());
1090 }
1091
TEST_F(ServiceDescriptorTest,MethodsByIndex)1092 TEST_F(ServiceDescriptorTest, MethodsByIndex) {
1093 ASSERT_EQ(2, service_->method_count());
1094 EXPECT_EQ(foo_, service_->method(0));
1095 EXPECT_EQ(bar_, service_->method(1));
1096 }
1097
TEST_F(ServiceDescriptorTest,FindMethodByName)1098 TEST_F(ServiceDescriptorTest, FindMethodByName) {
1099 EXPECT_EQ(foo_ , service_ ->FindMethodByName("Foo"));
1100 EXPECT_EQ(bar_ , service_ ->FindMethodByName("Bar"));
1101 EXPECT_EQ(foo2_, service2_->FindMethodByName("Foo"));
1102 EXPECT_EQ(baz2_, service2_->FindMethodByName("Baz"));
1103
1104 EXPECT_TRUE(service_ ->FindMethodByName("NoSuchMethod") == NULL);
1105 EXPECT_TRUE(service_ ->FindMethodByName("Baz" ) == NULL);
1106 EXPECT_TRUE(service2_->FindMethodByName("Bar" ) == NULL);
1107 }
1108
TEST_F(ServiceDescriptorTest,MethodName)1109 TEST_F(ServiceDescriptorTest, MethodName) {
1110 EXPECT_EQ("Foo", foo_->name());
1111 EXPECT_EQ("Bar", bar_->name());
1112 }
1113
TEST_F(ServiceDescriptorTest,MethodFullName)1114 TEST_F(ServiceDescriptorTest, MethodFullName) {
1115 EXPECT_EQ("TestService.Foo", foo_->full_name());
1116 EXPECT_EQ("TestService.Bar", bar_->full_name());
1117 EXPECT_EQ("corge.grault.TestService2.Foo", foo2_->full_name());
1118 EXPECT_EQ("corge.grault.TestService2.Baz", baz2_->full_name());
1119 }
1120
TEST_F(ServiceDescriptorTest,MethodIndex)1121 TEST_F(ServiceDescriptorTest, MethodIndex) {
1122 EXPECT_EQ(0, foo_->index());
1123 EXPECT_EQ(1, bar_->index());
1124 }
1125
TEST_F(ServiceDescriptorTest,MethodParent)1126 TEST_F(ServiceDescriptorTest, MethodParent) {
1127 EXPECT_EQ(service_, foo_->service());
1128 EXPECT_EQ(service_, bar_->service());
1129 }
1130
TEST_F(ServiceDescriptorTest,MethodInputType)1131 TEST_F(ServiceDescriptorTest, MethodInputType) {
1132 EXPECT_EQ(foo_request_, foo_->input_type());
1133 EXPECT_EQ(bar_request_, bar_->input_type());
1134 }
1135
TEST_F(ServiceDescriptorTest,MethodOutputType)1136 TEST_F(ServiceDescriptorTest, MethodOutputType) {
1137 EXPECT_EQ(foo_response_, foo_->output_type());
1138 EXPECT_EQ(bar_response_, bar_->output_type());
1139 }
1140
1141 // ===================================================================
1142
1143 // Test nested types.
1144 class NestedDescriptorTest : public testing::Test {
1145 protected:
SetUp()1146 virtual void SetUp() {
1147 // Build descriptors for the following definitions:
1148 //
1149 // // in "foo.proto"
1150 // message TestMessage {
1151 // message Foo {}
1152 // message Bar {}
1153 // enum Baz { A = 1; }
1154 // enum Qux { B = 1; }
1155 // }
1156 //
1157 // // in "bar.proto"
1158 // package corge.grault;
1159 // message TestMessage2 {
1160 // message Foo {}
1161 // message Baz {}
1162 // enum Qux { A = 1; }
1163 // enum Quux { C = 1; }
1164 // }
1165 //
1166 // TestMessage2 is primarily here to test FindNestedTypeByName and friends.
1167 // All messages created from the same DescriptorPool share the same lookup
1168 // table, so we need to insure that they don't interfere.
1169 //
1170 // We add enum values to the enums in order to test searching for enum
1171 // values across a message's scope.
1172
1173 FileDescriptorProto foo_file;
1174 foo_file.set_name("foo.proto");
1175
1176 DescriptorProto* message = AddMessage(&foo_file, "TestMessage");
1177 AddNestedMessage(message, "Foo");
1178 AddNestedMessage(message, "Bar");
1179 EnumDescriptorProto* baz = AddNestedEnum(message, "Baz");
1180 AddEnumValue(baz, "A", 1);
1181 EnumDescriptorProto* qux = AddNestedEnum(message, "Qux");
1182 AddEnumValue(qux, "B", 1);
1183
1184 FileDescriptorProto bar_file;
1185 bar_file.set_name("bar.proto");
1186 bar_file.set_package("corge.grault");
1187
1188 DescriptorProto* message2 = AddMessage(&bar_file, "TestMessage2");
1189 AddNestedMessage(message2, "Foo");
1190 AddNestedMessage(message2, "Baz");
1191 EnumDescriptorProto* qux2 = AddNestedEnum(message2, "Qux");
1192 AddEnumValue(qux2, "A", 1);
1193 EnumDescriptorProto* quux2 = AddNestedEnum(message2, "Quux");
1194 AddEnumValue(quux2, "C", 1);
1195
1196 // Build the descriptors and get the pointers.
1197 foo_file_ = pool_.BuildFile(foo_file);
1198 ASSERT_TRUE(foo_file_ != NULL);
1199
1200 bar_file_ = pool_.BuildFile(bar_file);
1201 ASSERT_TRUE(bar_file_ != NULL);
1202
1203 ASSERT_EQ(1, foo_file_->message_type_count());
1204 message_ = foo_file_->message_type(0);
1205
1206 ASSERT_EQ(2, message_->nested_type_count());
1207 foo_ = message_->nested_type(0);
1208 bar_ = message_->nested_type(1);
1209
1210 ASSERT_EQ(2, message_->enum_type_count());
1211 baz_ = message_->enum_type(0);
1212 qux_ = message_->enum_type(1);
1213
1214 ASSERT_EQ(1, baz_->value_count());
1215 a_ = baz_->value(0);
1216 ASSERT_EQ(1, qux_->value_count());
1217 b_ = qux_->value(0);
1218
1219 ASSERT_EQ(1, bar_file_->message_type_count());
1220 message2_ = bar_file_->message_type(0);
1221
1222 ASSERT_EQ(2, message2_->nested_type_count());
1223 foo2_ = message2_->nested_type(0);
1224 baz2_ = message2_->nested_type(1);
1225
1226 ASSERT_EQ(2, message2_->enum_type_count());
1227 qux2_ = message2_->enum_type(0);
1228 quux2_ = message2_->enum_type(1);
1229
1230 ASSERT_EQ(1, qux2_->value_count());
1231 a2_ = qux2_->value(0);
1232 ASSERT_EQ(1, quux2_->value_count());
1233 c2_ = quux2_->value(0);
1234 }
1235
1236 DescriptorPool pool_;
1237
1238 const FileDescriptor* foo_file_;
1239 const FileDescriptor* bar_file_;
1240
1241 const Descriptor* message_;
1242 const Descriptor* message2_;
1243
1244 const Descriptor* foo_;
1245 const Descriptor* bar_;
1246 const EnumDescriptor* baz_;
1247 const EnumDescriptor* qux_;
1248 const EnumValueDescriptor* a_;
1249 const EnumValueDescriptor* b_;
1250
1251 const Descriptor* foo2_;
1252 const Descriptor* baz2_;
1253 const EnumDescriptor* qux2_;
1254 const EnumDescriptor* quux2_;
1255 const EnumValueDescriptor* a2_;
1256 const EnumValueDescriptor* c2_;
1257 };
1258
TEST_F(NestedDescriptorTest,MessageName)1259 TEST_F(NestedDescriptorTest, MessageName) {
1260 EXPECT_EQ("Foo", foo_ ->name());
1261 EXPECT_EQ("Bar", bar_ ->name());
1262 EXPECT_EQ("Foo", foo2_->name());
1263 EXPECT_EQ("Baz", baz2_->name());
1264
1265 EXPECT_EQ("TestMessage.Foo", foo_->full_name());
1266 EXPECT_EQ("TestMessage.Bar", bar_->full_name());
1267 EXPECT_EQ("corge.grault.TestMessage2.Foo", foo2_->full_name());
1268 EXPECT_EQ("corge.grault.TestMessage2.Baz", baz2_->full_name());
1269 }
1270
TEST_F(NestedDescriptorTest,MessageContainingType)1271 TEST_F(NestedDescriptorTest, MessageContainingType) {
1272 EXPECT_EQ(message_ , foo_ ->containing_type());
1273 EXPECT_EQ(message_ , bar_ ->containing_type());
1274 EXPECT_EQ(message2_, foo2_->containing_type());
1275 EXPECT_EQ(message2_, baz2_->containing_type());
1276 }
1277
TEST_F(NestedDescriptorTest,NestedMessagesByIndex)1278 TEST_F(NestedDescriptorTest, NestedMessagesByIndex) {
1279 ASSERT_EQ(2, message_->nested_type_count());
1280 EXPECT_EQ(foo_, message_->nested_type(0));
1281 EXPECT_EQ(bar_, message_->nested_type(1));
1282 }
1283
TEST_F(NestedDescriptorTest,FindFieldByNameDoesntFindNestedTypes)1284 TEST_F(NestedDescriptorTest, FindFieldByNameDoesntFindNestedTypes) {
1285 EXPECT_TRUE(message_->FindFieldByName("Foo") == NULL);
1286 EXPECT_TRUE(message_->FindFieldByName("Qux") == NULL);
1287 EXPECT_TRUE(message_->FindExtensionByName("Foo") == NULL);
1288 EXPECT_TRUE(message_->FindExtensionByName("Qux") == NULL);
1289 }
1290
TEST_F(NestedDescriptorTest,FindNestedTypeByName)1291 TEST_F(NestedDescriptorTest, FindNestedTypeByName) {
1292 EXPECT_EQ(foo_ , message_ ->FindNestedTypeByName("Foo"));
1293 EXPECT_EQ(bar_ , message_ ->FindNestedTypeByName("Bar"));
1294 EXPECT_EQ(foo2_, message2_->FindNestedTypeByName("Foo"));
1295 EXPECT_EQ(baz2_, message2_->FindNestedTypeByName("Baz"));
1296
1297 EXPECT_TRUE(message_ ->FindNestedTypeByName("NoSuchType") == NULL);
1298 EXPECT_TRUE(message_ ->FindNestedTypeByName("Baz" ) == NULL);
1299 EXPECT_TRUE(message2_->FindNestedTypeByName("Bar" ) == NULL);
1300
1301 EXPECT_TRUE(message_->FindNestedTypeByName("Qux") == NULL);
1302 }
1303
TEST_F(NestedDescriptorTest,EnumName)1304 TEST_F(NestedDescriptorTest, EnumName) {
1305 EXPECT_EQ("Baz" , baz_ ->name());
1306 EXPECT_EQ("Qux" , qux_ ->name());
1307 EXPECT_EQ("Qux" , qux2_->name());
1308 EXPECT_EQ("Quux", quux2_->name());
1309
1310 EXPECT_EQ("TestMessage.Baz", baz_->full_name());
1311 EXPECT_EQ("TestMessage.Qux", qux_->full_name());
1312 EXPECT_EQ("corge.grault.TestMessage2.Qux" , qux2_ ->full_name());
1313 EXPECT_EQ("corge.grault.TestMessage2.Quux", quux2_->full_name());
1314 }
1315
TEST_F(NestedDescriptorTest,EnumContainingType)1316 TEST_F(NestedDescriptorTest, EnumContainingType) {
1317 EXPECT_EQ(message_ , baz_ ->containing_type());
1318 EXPECT_EQ(message_ , qux_ ->containing_type());
1319 EXPECT_EQ(message2_, qux2_ ->containing_type());
1320 EXPECT_EQ(message2_, quux2_->containing_type());
1321 }
1322
TEST_F(NestedDescriptorTest,NestedEnumsByIndex)1323 TEST_F(NestedDescriptorTest, NestedEnumsByIndex) {
1324 ASSERT_EQ(2, message_->nested_type_count());
1325 EXPECT_EQ(foo_, message_->nested_type(0));
1326 EXPECT_EQ(bar_, message_->nested_type(1));
1327 }
1328
TEST_F(NestedDescriptorTest,FindEnumTypeByName)1329 TEST_F(NestedDescriptorTest, FindEnumTypeByName) {
1330 EXPECT_EQ(baz_ , message_ ->FindEnumTypeByName("Baz" ));
1331 EXPECT_EQ(qux_ , message_ ->FindEnumTypeByName("Qux" ));
1332 EXPECT_EQ(qux2_ , message2_->FindEnumTypeByName("Qux" ));
1333 EXPECT_EQ(quux2_, message2_->FindEnumTypeByName("Quux"));
1334
1335 EXPECT_TRUE(message_ ->FindEnumTypeByName("NoSuchType") == NULL);
1336 EXPECT_TRUE(message_ ->FindEnumTypeByName("Quux" ) == NULL);
1337 EXPECT_TRUE(message2_->FindEnumTypeByName("Baz" ) == NULL);
1338
1339 EXPECT_TRUE(message_->FindEnumTypeByName("Foo") == NULL);
1340 }
1341
TEST_F(NestedDescriptorTest,FindEnumValueByName)1342 TEST_F(NestedDescriptorTest, FindEnumValueByName) {
1343 EXPECT_EQ(a_ , message_ ->FindEnumValueByName("A"));
1344 EXPECT_EQ(b_ , message_ ->FindEnumValueByName("B"));
1345 EXPECT_EQ(a2_, message2_->FindEnumValueByName("A"));
1346 EXPECT_EQ(c2_, message2_->FindEnumValueByName("C"));
1347
1348 EXPECT_TRUE(message_ ->FindEnumValueByName("NO_SUCH_VALUE") == NULL);
1349 EXPECT_TRUE(message_ ->FindEnumValueByName("C" ) == NULL);
1350 EXPECT_TRUE(message2_->FindEnumValueByName("B" ) == NULL);
1351
1352 EXPECT_TRUE(message_->FindEnumValueByName("Foo") == NULL);
1353 }
1354
1355 // ===================================================================
1356
1357 // Test extensions.
1358 class ExtensionDescriptorTest : public testing::Test {
1359 protected:
SetUp()1360 virtual void SetUp() {
1361 // Build descriptors for the following definitions:
1362 //
1363 // enum Baz {}
1364 // message Qux {}
1365 //
1366 // message Foo {
1367 // extensions 10 to 19;
1368 // extensions 30 to 39;
1369 // }
1370 // extends Foo with optional int32 foo_int32 = 10;
1371 // extends Foo with repeated TestEnum foo_enum = 19;
1372 // message Bar {
1373 // extends Foo with optional Qux foo_message = 30;
1374 // // (using Qux as the group type)
1375 // extends Foo with repeated group foo_group = 39;
1376 // }
1377
1378 FileDescriptorProto foo_file;
1379 foo_file.set_name("foo.proto");
1380
1381 AddEmptyEnum(&foo_file, "Baz");
1382 AddMessage(&foo_file, "Qux");
1383
1384 DescriptorProto* foo = AddMessage(&foo_file, "Foo");
1385 AddExtensionRange(foo, 10, 20);
1386 AddExtensionRange(foo, 30, 40);
1387
1388 AddExtension(&foo_file, "Foo", "foo_int32", 10,
1389 FieldDescriptorProto::LABEL_OPTIONAL,
1390 FieldDescriptorProto::TYPE_INT32);
1391 AddExtension(&foo_file, "Foo", "foo_enum", 19,
1392 FieldDescriptorProto::LABEL_REPEATED,
1393 FieldDescriptorProto::TYPE_ENUM)
1394 ->set_type_name("Baz");
1395
1396 DescriptorProto* bar = AddMessage(&foo_file, "Bar");
1397 AddNestedExtension(bar, "Foo", "foo_message", 30,
1398 FieldDescriptorProto::LABEL_OPTIONAL,
1399 FieldDescriptorProto::TYPE_MESSAGE)
1400 ->set_type_name("Qux");
1401 AddNestedExtension(bar, "Foo", "foo_group", 39,
1402 FieldDescriptorProto::LABEL_REPEATED,
1403 FieldDescriptorProto::TYPE_GROUP)
1404 ->set_type_name("Qux");
1405
1406 // Build the descriptors and get the pointers.
1407 foo_file_ = pool_.BuildFile(foo_file);
1408 ASSERT_TRUE(foo_file_ != NULL);
1409
1410 ASSERT_EQ(1, foo_file_->enum_type_count());
1411 baz_ = foo_file_->enum_type(0);
1412
1413 ASSERT_EQ(3, foo_file_->message_type_count());
1414 qux_ = foo_file_->message_type(0);
1415 foo_ = foo_file_->message_type(1);
1416 bar_ = foo_file_->message_type(2);
1417 }
1418
1419 DescriptorPool pool_;
1420
1421 const FileDescriptor* foo_file_;
1422
1423 const Descriptor* foo_;
1424 const Descriptor* bar_;
1425 const EnumDescriptor* baz_;
1426 const Descriptor* qux_;
1427 };
1428
TEST_F(ExtensionDescriptorTest,ExtensionRanges)1429 TEST_F(ExtensionDescriptorTest, ExtensionRanges) {
1430 EXPECT_EQ(0, bar_->extension_range_count());
1431 ASSERT_EQ(2, foo_->extension_range_count());
1432
1433 EXPECT_EQ(10, foo_->extension_range(0)->start);
1434 EXPECT_EQ(30, foo_->extension_range(1)->start);
1435
1436 EXPECT_EQ(20, foo_->extension_range(0)->end);
1437 EXPECT_EQ(40, foo_->extension_range(1)->end);
1438 };
1439
TEST_F(ExtensionDescriptorTest,Extensions)1440 TEST_F(ExtensionDescriptorTest, Extensions) {
1441 EXPECT_EQ(0, foo_->extension_count());
1442 ASSERT_EQ(2, foo_file_->extension_count());
1443 ASSERT_EQ(2, bar_->extension_count());
1444
1445 EXPECT_TRUE(foo_file_->extension(0)->is_extension());
1446 EXPECT_TRUE(foo_file_->extension(1)->is_extension());
1447 EXPECT_TRUE(bar_->extension(0)->is_extension());
1448 EXPECT_TRUE(bar_->extension(1)->is_extension());
1449
1450 EXPECT_EQ("foo_int32" , foo_file_->extension(0)->name());
1451 EXPECT_EQ("foo_enum" , foo_file_->extension(1)->name());
1452 EXPECT_EQ("foo_message", bar_->extension(0)->name());
1453 EXPECT_EQ("foo_group" , bar_->extension(1)->name());
1454
1455 EXPECT_EQ(10, foo_file_->extension(0)->number());
1456 EXPECT_EQ(19, foo_file_->extension(1)->number());
1457 EXPECT_EQ(30, bar_->extension(0)->number());
1458 EXPECT_EQ(39, bar_->extension(1)->number());
1459
1460 EXPECT_EQ(FieldDescriptor::TYPE_INT32 , foo_file_->extension(0)->type());
1461 EXPECT_EQ(FieldDescriptor::TYPE_ENUM , foo_file_->extension(1)->type());
1462 EXPECT_EQ(FieldDescriptor::TYPE_MESSAGE, bar_->extension(0)->type());
1463 EXPECT_EQ(FieldDescriptor::TYPE_GROUP , bar_->extension(1)->type());
1464
1465 EXPECT_EQ(baz_, foo_file_->extension(1)->enum_type());
1466 EXPECT_EQ(qux_, bar_->extension(0)->message_type());
1467 EXPECT_EQ(qux_, bar_->extension(1)->message_type());
1468
1469 EXPECT_EQ(FieldDescriptor::LABEL_OPTIONAL, foo_file_->extension(0)->label());
1470 EXPECT_EQ(FieldDescriptor::LABEL_REPEATED, foo_file_->extension(1)->label());
1471 EXPECT_EQ(FieldDescriptor::LABEL_OPTIONAL, bar_->extension(0)->label());
1472 EXPECT_EQ(FieldDescriptor::LABEL_REPEATED, bar_->extension(1)->label());
1473
1474 EXPECT_EQ(foo_, foo_file_->extension(0)->containing_type());
1475 EXPECT_EQ(foo_, foo_file_->extension(1)->containing_type());
1476 EXPECT_EQ(foo_, bar_->extension(0)->containing_type());
1477 EXPECT_EQ(foo_, bar_->extension(1)->containing_type());
1478
1479 EXPECT_TRUE(foo_file_->extension(0)->extension_scope() == NULL);
1480 EXPECT_TRUE(foo_file_->extension(1)->extension_scope() == NULL);
1481 EXPECT_EQ(bar_, bar_->extension(0)->extension_scope());
1482 EXPECT_EQ(bar_, bar_->extension(1)->extension_scope());
1483 };
1484
TEST_F(ExtensionDescriptorTest,IsExtensionNumber)1485 TEST_F(ExtensionDescriptorTest, IsExtensionNumber) {
1486 EXPECT_FALSE(foo_->IsExtensionNumber( 9));
1487 EXPECT_TRUE (foo_->IsExtensionNumber(10));
1488 EXPECT_TRUE (foo_->IsExtensionNumber(19));
1489 EXPECT_FALSE(foo_->IsExtensionNumber(20));
1490 EXPECT_FALSE(foo_->IsExtensionNumber(29));
1491 EXPECT_TRUE (foo_->IsExtensionNumber(30));
1492 EXPECT_TRUE (foo_->IsExtensionNumber(39));
1493 EXPECT_FALSE(foo_->IsExtensionNumber(40));
1494 }
1495
TEST_F(ExtensionDescriptorTest,FindExtensionByName)1496 TEST_F(ExtensionDescriptorTest, FindExtensionByName) {
1497 // Note that FileDescriptor::FindExtensionByName() is tested by
1498 // FileDescriptorTest.
1499 ASSERT_EQ(2, bar_->extension_count());
1500
1501 EXPECT_EQ(bar_->extension(0), bar_->FindExtensionByName("foo_message"));
1502 EXPECT_EQ(bar_->extension(1), bar_->FindExtensionByName("foo_group" ));
1503
1504 EXPECT_TRUE(bar_->FindExtensionByName("no_such_extension") == NULL);
1505 EXPECT_TRUE(foo_->FindExtensionByName("foo_int32") == NULL);
1506 EXPECT_TRUE(foo_->FindExtensionByName("foo_message") == NULL);
1507 }
1508
TEST_F(ExtensionDescriptorTest,FindAllExtensions)1509 TEST_F(ExtensionDescriptorTest, FindAllExtensions) {
1510 vector<const FieldDescriptor*> extensions;
1511 pool_.FindAllExtensions(foo_, &extensions);
1512 ASSERT_EQ(4, extensions.size());
1513 EXPECT_EQ(10, extensions[0]->number());
1514 EXPECT_EQ(19, extensions[1]->number());
1515 EXPECT_EQ(30, extensions[2]->number());
1516 EXPECT_EQ(39, extensions[3]->number());
1517 }
1518
1519 // ===================================================================
1520
1521 class MiscTest : public testing::Test {
1522 protected:
1523 // Function which makes a field descriptor of the given type.
GetFieldDescriptorOfType(FieldDescriptor::Type type)1524 const FieldDescriptor* GetFieldDescriptorOfType(FieldDescriptor::Type type) {
1525 FileDescriptorProto file_proto;
1526 file_proto.set_name("foo.proto");
1527 AddEmptyEnum(&file_proto, "DummyEnum");
1528
1529 DescriptorProto* message = AddMessage(&file_proto, "TestMessage");
1530 FieldDescriptorProto* field =
1531 AddField(message, "foo", 1, FieldDescriptorProto::LABEL_OPTIONAL,
1532 static_cast<FieldDescriptorProto::Type>(static_cast<int>(type)));
1533
1534 if (type == FieldDescriptor::TYPE_MESSAGE ||
1535 type == FieldDescriptor::TYPE_GROUP) {
1536 field->set_type_name("TestMessage");
1537 } else if (type == FieldDescriptor::TYPE_ENUM) {
1538 field->set_type_name("DummyEnum");
1539 }
1540
1541 // Build the descriptors and get the pointers.
1542 pool_.reset(new DescriptorPool());
1543 const FileDescriptor* file = pool_->BuildFile(file_proto);
1544
1545 if (file != NULL &&
1546 file->message_type_count() == 1 &&
1547 file->message_type(0)->field_count() == 1) {
1548 return file->message_type(0)->field(0);
1549 } else {
1550 return NULL;
1551 }
1552 }
1553
GetTypeNameForFieldType(FieldDescriptor::Type type)1554 const char* GetTypeNameForFieldType(FieldDescriptor::Type type) {
1555 const FieldDescriptor* field = GetFieldDescriptorOfType(type);
1556 return field != NULL ? field->type_name() : "";
1557 }
1558
GetCppTypeForFieldType(FieldDescriptor::Type type)1559 FieldDescriptor::CppType GetCppTypeForFieldType(FieldDescriptor::Type type) {
1560 const FieldDescriptor* field = GetFieldDescriptorOfType(type);
1561 return field != NULL ? field->cpp_type() :
1562 static_cast<FieldDescriptor::CppType>(0);
1563 }
1564
GetCppTypeNameForFieldType(FieldDescriptor::Type type)1565 const char* GetCppTypeNameForFieldType(FieldDescriptor::Type type) {
1566 const FieldDescriptor* field = GetFieldDescriptorOfType(type);
1567 return field != NULL ? field->cpp_type_name() : "";
1568 }
1569
1570 scoped_ptr<DescriptorPool> pool_;
1571 };
1572
TEST_F(MiscTest,TypeNames)1573 TEST_F(MiscTest, TypeNames) {
1574 // Test that correct type names are returned.
1575
1576 typedef FieldDescriptor FD; // avoid ugly line wrapping
1577
1578 EXPECT_STREQ("double" , GetTypeNameForFieldType(FD::TYPE_DOUBLE ));
1579 EXPECT_STREQ("float" , GetTypeNameForFieldType(FD::TYPE_FLOAT ));
1580 EXPECT_STREQ("int64" , GetTypeNameForFieldType(FD::TYPE_INT64 ));
1581 EXPECT_STREQ("uint64" , GetTypeNameForFieldType(FD::TYPE_UINT64 ));
1582 EXPECT_STREQ("int32" , GetTypeNameForFieldType(FD::TYPE_INT32 ));
1583 EXPECT_STREQ("fixed64" , GetTypeNameForFieldType(FD::TYPE_FIXED64 ));
1584 EXPECT_STREQ("fixed32" , GetTypeNameForFieldType(FD::TYPE_FIXED32 ));
1585 EXPECT_STREQ("bool" , GetTypeNameForFieldType(FD::TYPE_BOOL ));
1586 EXPECT_STREQ("string" , GetTypeNameForFieldType(FD::TYPE_STRING ));
1587 EXPECT_STREQ("group" , GetTypeNameForFieldType(FD::TYPE_GROUP ));
1588 EXPECT_STREQ("message" , GetTypeNameForFieldType(FD::TYPE_MESSAGE ));
1589 EXPECT_STREQ("bytes" , GetTypeNameForFieldType(FD::TYPE_BYTES ));
1590 EXPECT_STREQ("uint32" , GetTypeNameForFieldType(FD::TYPE_UINT32 ));
1591 EXPECT_STREQ("enum" , GetTypeNameForFieldType(FD::TYPE_ENUM ));
1592 EXPECT_STREQ("sfixed32", GetTypeNameForFieldType(FD::TYPE_SFIXED32));
1593 EXPECT_STREQ("sfixed64", GetTypeNameForFieldType(FD::TYPE_SFIXED64));
1594 EXPECT_STREQ("sint32" , GetTypeNameForFieldType(FD::TYPE_SINT32 ));
1595 EXPECT_STREQ("sint64" , GetTypeNameForFieldType(FD::TYPE_SINT64 ));
1596 }
1597
TEST_F(MiscTest,CppTypes)1598 TEST_F(MiscTest, CppTypes) {
1599 // Test that CPP types are assigned correctly.
1600
1601 typedef FieldDescriptor FD; // avoid ugly line wrapping
1602
1603 EXPECT_EQ(FD::CPPTYPE_DOUBLE , GetCppTypeForFieldType(FD::TYPE_DOUBLE ));
1604 EXPECT_EQ(FD::CPPTYPE_FLOAT , GetCppTypeForFieldType(FD::TYPE_FLOAT ));
1605 EXPECT_EQ(FD::CPPTYPE_INT64 , GetCppTypeForFieldType(FD::TYPE_INT64 ));
1606 EXPECT_EQ(FD::CPPTYPE_UINT64 , GetCppTypeForFieldType(FD::TYPE_UINT64 ));
1607 EXPECT_EQ(FD::CPPTYPE_INT32 , GetCppTypeForFieldType(FD::TYPE_INT32 ));
1608 EXPECT_EQ(FD::CPPTYPE_UINT64 , GetCppTypeForFieldType(FD::TYPE_FIXED64 ));
1609 EXPECT_EQ(FD::CPPTYPE_UINT32 , GetCppTypeForFieldType(FD::TYPE_FIXED32 ));
1610 EXPECT_EQ(FD::CPPTYPE_BOOL , GetCppTypeForFieldType(FD::TYPE_BOOL ));
1611 EXPECT_EQ(FD::CPPTYPE_STRING , GetCppTypeForFieldType(FD::TYPE_STRING ));
1612 EXPECT_EQ(FD::CPPTYPE_MESSAGE, GetCppTypeForFieldType(FD::TYPE_GROUP ));
1613 EXPECT_EQ(FD::CPPTYPE_MESSAGE, GetCppTypeForFieldType(FD::TYPE_MESSAGE ));
1614 EXPECT_EQ(FD::CPPTYPE_STRING , GetCppTypeForFieldType(FD::TYPE_BYTES ));
1615 EXPECT_EQ(FD::CPPTYPE_UINT32 , GetCppTypeForFieldType(FD::TYPE_UINT32 ));
1616 EXPECT_EQ(FD::CPPTYPE_ENUM , GetCppTypeForFieldType(FD::TYPE_ENUM ));
1617 EXPECT_EQ(FD::CPPTYPE_INT32 , GetCppTypeForFieldType(FD::TYPE_SFIXED32));
1618 EXPECT_EQ(FD::CPPTYPE_INT64 , GetCppTypeForFieldType(FD::TYPE_SFIXED64));
1619 EXPECT_EQ(FD::CPPTYPE_INT32 , GetCppTypeForFieldType(FD::TYPE_SINT32 ));
1620 EXPECT_EQ(FD::CPPTYPE_INT64 , GetCppTypeForFieldType(FD::TYPE_SINT64 ));
1621 }
1622
TEST_F(MiscTest,CppTypeNames)1623 TEST_F(MiscTest, CppTypeNames) {
1624 // Test that correct CPP type names are returned.
1625
1626 typedef FieldDescriptor FD; // avoid ugly line wrapping
1627
1628 EXPECT_STREQ("double" , GetCppTypeNameForFieldType(FD::TYPE_DOUBLE ));
1629 EXPECT_STREQ("float" , GetCppTypeNameForFieldType(FD::TYPE_FLOAT ));
1630 EXPECT_STREQ("int64" , GetCppTypeNameForFieldType(FD::TYPE_INT64 ));
1631 EXPECT_STREQ("uint64" , GetCppTypeNameForFieldType(FD::TYPE_UINT64 ));
1632 EXPECT_STREQ("int32" , GetCppTypeNameForFieldType(FD::TYPE_INT32 ));
1633 EXPECT_STREQ("uint64" , GetCppTypeNameForFieldType(FD::TYPE_FIXED64 ));
1634 EXPECT_STREQ("uint32" , GetCppTypeNameForFieldType(FD::TYPE_FIXED32 ));
1635 EXPECT_STREQ("bool" , GetCppTypeNameForFieldType(FD::TYPE_BOOL ));
1636 EXPECT_STREQ("string" , GetCppTypeNameForFieldType(FD::TYPE_STRING ));
1637 EXPECT_STREQ("message", GetCppTypeNameForFieldType(FD::TYPE_GROUP ));
1638 EXPECT_STREQ("message", GetCppTypeNameForFieldType(FD::TYPE_MESSAGE ));
1639 EXPECT_STREQ("string" , GetCppTypeNameForFieldType(FD::TYPE_BYTES ));
1640 EXPECT_STREQ("uint32" , GetCppTypeNameForFieldType(FD::TYPE_UINT32 ));
1641 EXPECT_STREQ("enum" , GetCppTypeNameForFieldType(FD::TYPE_ENUM ));
1642 EXPECT_STREQ("int32" , GetCppTypeNameForFieldType(FD::TYPE_SFIXED32));
1643 EXPECT_STREQ("int64" , GetCppTypeNameForFieldType(FD::TYPE_SFIXED64));
1644 EXPECT_STREQ("int32" , GetCppTypeNameForFieldType(FD::TYPE_SINT32 ));
1645 EXPECT_STREQ("int64" , GetCppTypeNameForFieldType(FD::TYPE_SINT64 ));
1646 }
1647
TEST_F(MiscTest,DefaultValues)1648 TEST_F(MiscTest, DefaultValues) {
1649 // Test that setting default values works.
1650 FileDescriptorProto file_proto;
1651 file_proto.set_name("foo.proto");
1652
1653 EnumDescriptorProto* enum_type_proto = AddEnum(&file_proto, "DummyEnum");
1654 AddEnumValue(enum_type_proto, "A", 1);
1655 AddEnumValue(enum_type_proto, "B", 2);
1656
1657 DescriptorProto* message_proto = AddMessage(&file_proto, "TestMessage");
1658
1659 typedef FieldDescriptorProto FD; // avoid ugly line wrapping
1660 const FD::Label label = FD::LABEL_OPTIONAL;
1661
1662 // Create fields of every CPP type with default values.
1663 AddField(message_proto, "int32" , 1, label, FD::TYPE_INT32 )
1664 ->set_default_value("-1");
1665 AddField(message_proto, "int64" , 2, label, FD::TYPE_INT64 )
1666 ->set_default_value("-1000000000000");
1667 AddField(message_proto, "uint32", 3, label, FD::TYPE_UINT32)
1668 ->set_default_value("42");
1669 AddField(message_proto, "uint64", 4, label, FD::TYPE_UINT64)
1670 ->set_default_value("2000000000000");
1671 AddField(message_proto, "float" , 5, label, FD::TYPE_FLOAT )
1672 ->set_default_value("4.5");
1673 AddField(message_proto, "double", 6, label, FD::TYPE_DOUBLE)
1674 ->set_default_value("10e100");
1675 AddField(message_proto, "bool" , 7, label, FD::TYPE_BOOL )
1676 ->set_default_value("true");
1677 AddField(message_proto, "string", 8, label, FD::TYPE_STRING)
1678 ->set_default_value("hello");
1679 AddField(message_proto, "data" , 9, label, FD::TYPE_BYTES )
1680 ->set_default_value("\\001\\002\\003");
1681
1682 FieldDescriptorProto* enum_field =
1683 AddField(message_proto, "enum", 10, label, FD::TYPE_ENUM);
1684 enum_field->set_type_name("DummyEnum");
1685 enum_field->set_default_value("B");
1686
1687 // Strings are allowed to have empty defaults. (At one point, due to
1688 // a bug, empty defaults for strings were rejected. Oops.)
1689 AddField(message_proto, "empty_string", 11, label, FD::TYPE_STRING)
1690 ->set_default_value("");
1691
1692 // Add a second set of fields with implicit defalut values.
1693 AddField(message_proto, "implicit_int32" , 21, label, FD::TYPE_INT32 );
1694 AddField(message_proto, "implicit_int64" , 22, label, FD::TYPE_INT64 );
1695 AddField(message_proto, "implicit_uint32", 23, label, FD::TYPE_UINT32);
1696 AddField(message_proto, "implicit_uint64", 24, label, FD::TYPE_UINT64);
1697 AddField(message_proto, "implicit_float" , 25, label, FD::TYPE_FLOAT );
1698 AddField(message_proto, "implicit_double", 26, label, FD::TYPE_DOUBLE);
1699 AddField(message_proto, "implicit_bool" , 27, label, FD::TYPE_BOOL );
1700 AddField(message_proto, "implicit_string", 28, label, FD::TYPE_STRING);
1701 AddField(message_proto, "implicit_data" , 29, label, FD::TYPE_BYTES );
1702 AddField(message_proto, "implicit_enum" , 30, label, FD::TYPE_ENUM)
1703 ->set_type_name("DummyEnum");
1704
1705 // Build it.
1706 DescriptorPool pool;
1707 const FileDescriptor* file = pool.BuildFile(file_proto);
1708 ASSERT_TRUE(file != NULL);
1709
1710 ASSERT_EQ(1, file->enum_type_count());
1711 const EnumDescriptor* enum_type = file->enum_type(0);
1712 ASSERT_EQ(2, enum_type->value_count());
1713 const EnumValueDescriptor* enum_value_a = enum_type->value(0);
1714 const EnumValueDescriptor* enum_value_b = enum_type->value(1);
1715
1716 ASSERT_EQ(1, file->message_type_count());
1717 const Descriptor* message = file->message_type(0);
1718
1719 ASSERT_EQ(21, message->field_count());
1720
1721 // Check the default values.
1722 ASSERT_TRUE(message->field(0)->has_default_value());
1723 ASSERT_TRUE(message->field(1)->has_default_value());
1724 ASSERT_TRUE(message->field(2)->has_default_value());
1725 ASSERT_TRUE(message->field(3)->has_default_value());
1726 ASSERT_TRUE(message->field(4)->has_default_value());
1727 ASSERT_TRUE(message->field(5)->has_default_value());
1728 ASSERT_TRUE(message->field(6)->has_default_value());
1729 ASSERT_TRUE(message->field(7)->has_default_value());
1730 ASSERT_TRUE(message->field(8)->has_default_value());
1731 ASSERT_TRUE(message->field(9)->has_default_value());
1732 ASSERT_TRUE(message->field(10)->has_default_value());
1733
1734 EXPECT_EQ(-1 , message->field(0)->default_value_int32 ());
1735 EXPECT_EQ(-GOOGLE_ULONGLONG(1000000000000),
1736 message->field(1)->default_value_int64 ());
1737 EXPECT_EQ(42 , message->field(2)->default_value_uint32());
1738 EXPECT_EQ(GOOGLE_ULONGLONG(2000000000000),
1739 message->field(3)->default_value_uint64());
1740 EXPECT_EQ(4.5 , message->field(4)->default_value_float ());
1741 EXPECT_EQ(10e100 , message->field(5)->default_value_double());
1742 EXPECT_TRUE( message->field(6)->default_value_bool ());
1743 EXPECT_EQ("hello" , message->field(7)->default_value_string());
1744 EXPECT_EQ("\001\002\003" , message->field(8)->default_value_string());
1745 EXPECT_EQ(enum_value_b , message->field(9)->default_value_enum ());
1746 EXPECT_EQ("" , message->field(10)->default_value_string());
1747
1748 ASSERT_FALSE(message->field(11)->has_default_value());
1749 ASSERT_FALSE(message->field(12)->has_default_value());
1750 ASSERT_FALSE(message->field(13)->has_default_value());
1751 ASSERT_FALSE(message->field(14)->has_default_value());
1752 ASSERT_FALSE(message->field(15)->has_default_value());
1753 ASSERT_FALSE(message->field(16)->has_default_value());
1754 ASSERT_FALSE(message->field(17)->has_default_value());
1755 ASSERT_FALSE(message->field(18)->has_default_value());
1756 ASSERT_FALSE(message->field(19)->has_default_value());
1757 ASSERT_FALSE(message->field(20)->has_default_value());
1758
1759 EXPECT_EQ(0 , message->field(11)->default_value_int32 ());
1760 EXPECT_EQ(0 , message->field(12)->default_value_int64 ());
1761 EXPECT_EQ(0 , message->field(13)->default_value_uint32());
1762 EXPECT_EQ(0 , message->field(14)->default_value_uint64());
1763 EXPECT_EQ(0.0f , message->field(15)->default_value_float ());
1764 EXPECT_EQ(0.0 , message->field(16)->default_value_double());
1765 EXPECT_FALSE( message->field(17)->default_value_bool ());
1766 EXPECT_EQ("" , message->field(18)->default_value_string());
1767 EXPECT_EQ("" , message->field(19)->default_value_string());
1768 EXPECT_EQ(enum_value_a, message->field(20)->default_value_enum());
1769 }
1770
TEST_F(MiscTest,FieldOptions)1771 TEST_F(MiscTest, FieldOptions) {
1772 // Try setting field options.
1773
1774 FileDescriptorProto file_proto;
1775 file_proto.set_name("foo.proto");
1776
1777 DescriptorProto* message_proto = AddMessage(&file_proto, "TestMessage");
1778 AddField(message_proto, "foo", 1,
1779 FieldDescriptorProto::LABEL_OPTIONAL,
1780 FieldDescriptorProto::TYPE_INT32);
1781 FieldDescriptorProto* bar_proto =
1782 AddField(message_proto, "bar", 2,
1783 FieldDescriptorProto::LABEL_OPTIONAL,
1784 FieldDescriptorProto::TYPE_INT32);
1785
1786 FieldOptions* options = bar_proto->mutable_options();
1787 options->set_ctype(FieldOptions::CORD);
1788
1789 // Build the descriptors and get the pointers.
1790 DescriptorPool pool;
1791 const FileDescriptor* file = pool.BuildFile(file_proto);
1792 ASSERT_TRUE(file != NULL);
1793
1794 ASSERT_EQ(1, file->message_type_count());
1795 const Descriptor* message = file->message_type(0);
1796
1797 ASSERT_EQ(2, message->field_count());
1798 const FieldDescriptor* foo = message->field(0);
1799 const FieldDescriptor* bar = message->field(1);
1800
1801 // "foo" had no options set, so it should return the default options.
1802 EXPECT_EQ(&FieldOptions::default_instance(), &foo->options());
1803
1804 // "bar" had options set.
1805 EXPECT_NE(&FieldOptions::default_instance(), options);
1806 EXPECT_TRUE(bar->options().has_ctype());
1807 EXPECT_EQ(FieldOptions::CORD, bar->options().ctype());
1808 }
1809
1810 // ===================================================================
1811 enum DescriptorPoolMode {
1812 NO_DATABASE,
1813 FALLBACK_DATABASE
1814 };
1815
1816 class AllowUnknownDependenciesTest
1817 : public testing::TestWithParam<DescriptorPoolMode> {
1818 protected:
mode()1819 DescriptorPoolMode mode() {
1820 return GetParam();
1821 }
1822
SetUp()1823 virtual void SetUp() {
1824 FileDescriptorProto foo_proto, bar_proto;
1825
1826 switch (mode()) {
1827 case NO_DATABASE:
1828 pool_.reset(new DescriptorPool);
1829 break;
1830 case FALLBACK_DATABASE:
1831 pool_.reset(new DescriptorPool(&db_));
1832 break;
1833 }
1834
1835 pool_->AllowUnknownDependencies();
1836
1837 ASSERT_TRUE(TextFormat::ParseFromString(
1838 "name: 'foo.proto'"
1839 "dependency: 'bar.proto'"
1840 "dependency: 'baz.proto'"
1841 "message_type {"
1842 " name: 'Foo'"
1843 " field { name:'bar' number:1 label:LABEL_OPTIONAL type_name:'Bar' }"
1844 " field { name:'baz' number:2 label:LABEL_OPTIONAL type_name:'Baz' }"
1845 " field { name:'qux' number:3 label:LABEL_OPTIONAL"
1846 " type_name: '.corge.Qux'"
1847 " type: TYPE_ENUM"
1848 " options {"
1849 " uninterpreted_option {"
1850 " name {"
1851 " name_part: 'grault'"
1852 " is_extension: true"
1853 " }"
1854 " positive_int_value: 1234"
1855 " }"
1856 " }"
1857 " }"
1858 "}",
1859 &foo_proto));
1860 ASSERT_TRUE(TextFormat::ParseFromString(
1861 "name: 'bar.proto'"
1862 "message_type { name: 'Bar' }",
1863 &bar_proto));
1864
1865 // Collect pointers to stuff.
1866 bar_file_ = BuildFile(bar_proto);
1867 ASSERT_TRUE(bar_file_ != NULL);
1868
1869 ASSERT_EQ(1, bar_file_->message_type_count());
1870 bar_type_ = bar_file_->message_type(0);
1871
1872 foo_file_ = BuildFile(foo_proto);
1873 ASSERT_TRUE(foo_file_ != NULL);
1874
1875 ASSERT_EQ(1, foo_file_->message_type_count());
1876 foo_type_ = foo_file_->message_type(0);
1877
1878 ASSERT_EQ(3, foo_type_->field_count());
1879 bar_field_ = foo_type_->field(0);
1880 baz_field_ = foo_type_->field(1);
1881 qux_field_ = foo_type_->field(2);
1882 }
1883
BuildFile(const FileDescriptorProto & proto)1884 const FileDescriptor* BuildFile(const FileDescriptorProto& proto) {
1885 switch (mode()) {
1886 case NO_DATABASE:
1887 return pool_->BuildFile(proto);
1888 break;
1889 case FALLBACK_DATABASE: {
1890 EXPECT_TRUE(db_.Add(proto));
1891 return pool_->FindFileByName(proto.name());
1892 }
1893 }
1894 GOOGLE_LOG(FATAL) << "Can't get here.";
1895 return NULL;
1896 }
1897
1898 const FileDescriptor* bar_file_;
1899 const Descriptor* bar_type_;
1900 const FileDescriptor* foo_file_;
1901 const Descriptor* foo_type_;
1902 const FieldDescriptor* bar_field_;
1903 const FieldDescriptor* baz_field_;
1904 const FieldDescriptor* qux_field_;
1905
1906 SimpleDescriptorDatabase db_; // used if in FALLBACK_DATABASE mode.
1907 scoped_ptr<DescriptorPool> pool_;
1908 };
1909
TEST_P(AllowUnknownDependenciesTest,PlaceholderFile)1910 TEST_P(AllowUnknownDependenciesTest, PlaceholderFile) {
1911 ASSERT_EQ(2, foo_file_->dependency_count());
1912 EXPECT_EQ(bar_file_, foo_file_->dependency(0));
1913
1914 const FileDescriptor* baz_file = foo_file_->dependency(1);
1915 EXPECT_EQ("baz.proto", baz_file->name());
1916 EXPECT_EQ(0, baz_file->message_type_count());
1917
1918 // Placeholder files should not be findable.
1919 EXPECT_EQ(bar_file_, pool_->FindFileByName(bar_file_->name()));
1920 EXPECT_TRUE(pool_->FindFileByName(baz_file->name()) == NULL);
1921 }
1922
TEST_P(AllowUnknownDependenciesTest,PlaceholderTypes)1923 TEST_P(AllowUnknownDependenciesTest, PlaceholderTypes) {
1924 ASSERT_EQ(FieldDescriptor::TYPE_MESSAGE, bar_field_->type());
1925 EXPECT_EQ(bar_type_, bar_field_->message_type());
1926
1927 ASSERT_EQ(FieldDescriptor::TYPE_MESSAGE, baz_field_->type());
1928 const Descriptor* baz_type = baz_field_->message_type();
1929 EXPECT_EQ("Baz", baz_type->name());
1930 EXPECT_EQ("Baz", baz_type->full_name());
1931 EXPECT_EQ("Baz.placeholder.proto", baz_type->file()->name());
1932 EXPECT_EQ(0, baz_type->extension_range_count());
1933
1934 ASSERT_EQ(FieldDescriptor::TYPE_ENUM, qux_field_->type());
1935 const EnumDescriptor* qux_type = qux_field_->enum_type();
1936 EXPECT_EQ("Qux", qux_type->name());
1937 EXPECT_EQ("corge.Qux", qux_type->full_name());
1938 EXPECT_EQ("corge.Qux.placeholder.proto", qux_type->file()->name());
1939
1940 // Placeholder types should not be findable.
1941 EXPECT_EQ(bar_type_, pool_->FindMessageTypeByName(bar_type_->full_name()));
1942 EXPECT_TRUE(pool_->FindMessageTypeByName(baz_type->full_name()) == NULL);
1943 EXPECT_TRUE(pool_->FindEnumTypeByName(qux_type->full_name()) == NULL);
1944 }
1945
TEST_P(AllowUnknownDependenciesTest,CopyTo)1946 TEST_P(AllowUnknownDependenciesTest, CopyTo) {
1947 // FieldDescriptor::CopyTo() should write non-fully-qualified type names
1948 // for placeholder types which were not originally fully-qualified.
1949 FieldDescriptorProto proto;
1950
1951 // Bar is not a placeholder, so it is fully-qualified.
1952 bar_field_->CopyTo(&proto);
1953 EXPECT_EQ(".Bar", proto.type_name());
1954 EXPECT_EQ(FieldDescriptorProto::TYPE_MESSAGE, proto.type());
1955
1956 // Baz is an unqualified placeholder.
1957 proto.Clear();
1958 baz_field_->CopyTo(&proto);
1959 EXPECT_EQ("Baz", proto.type_name());
1960 EXPECT_FALSE(proto.has_type());
1961
1962 // Qux is a fully-qualified placeholder.
1963 proto.Clear();
1964 qux_field_->CopyTo(&proto);
1965 EXPECT_EQ(".corge.Qux", proto.type_name());
1966 EXPECT_EQ(FieldDescriptorProto::TYPE_ENUM, proto.type());
1967 }
1968
TEST_P(AllowUnknownDependenciesTest,CustomOptions)1969 TEST_P(AllowUnknownDependenciesTest, CustomOptions) {
1970 // Qux should still have the uninterpreted option attached.
1971 ASSERT_EQ(1, qux_field_->options().uninterpreted_option_size());
1972 const UninterpretedOption& option =
1973 qux_field_->options().uninterpreted_option(0);
1974 ASSERT_EQ(1, option.name_size());
1975 EXPECT_EQ("grault", option.name(0).name_part());
1976 }
1977
TEST_P(AllowUnknownDependenciesTest,UnknownExtendee)1978 TEST_P(AllowUnknownDependenciesTest, UnknownExtendee) {
1979 // Test that we can extend an unknown type. This is slightly tricky because
1980 // it means that the placeholder type must have an extension range.
1981
1982 FileDescriptorProto extension_proto;
1983
1984 ASSERT_TRUE(TextFormat::ParseFromString(
1985 "name: 'extension.proto'"
1986 "extension { extendee: 'UnknownType' name:'some_extension' number:123"
1987 " label:LABEL_OPTIONAL type:TYPE_INT32 }",
1988 &extension_proto));
1989 const FileDescriptor* file = BuildFile(extension_proto);
1990
1991 ASSERT_TRUE(file != NULL);
1992
1993 ASSERT_EQ(1, file->extension_count());
1994 const Descriptor* extendee = file->extension(0)->containing_type();
1995 EXPECT_EQ("UnknownType", extendee->name());
1996 ASSERT_EQ(1, extendee->extension_range_count());
1997 EXPECT_EQ(1, extendee->extension_range(0)->start);
1998 EXPECT_EQ(FieldDescriptor::kMaxNumber + 1, extendee->extension_range(0)->end);
1999 }
2000
TEST_P(AllowUnknownDependenciesTest,CustomOption)2001 TEST_P(AllowUnknownDependenciesTest, CustomOption) {
2002 // Test that we can use a custom option without having parsed
2003 // descriptor.proto.
2004
2005 FileDescriptorProto option_proto;
2006
2007 ASSERT_TRUE(TextFormat::ParseFromString(
2008 "name: \"unknown_custom_options.proto\" "
2009 "dependency: \"google/protobuf/descriptor.proto\" "
2010 "extension { "
2011 " extendee: \"google.protobuf.FileOptions\" "
2012 " name: \"some_option\" "
2013 " number: 123456 "
2014 " label: LABEL_OPTIONAL "
2015 " type: TYPE_INT32 "
2016 "} "
2017 "options { "
2018 " uninterpreted_option { "
2019 " name { "
2020 " name_part: \"some_option\" "
2021 " is_extension: true "
2022 " } "
2023 " positive_int_value: 1234 "
2024 " } "
2025 " uninterpreted_option { "
2026 " name { "
2027 " name_part: \"unknown_option\" "
2028 " is_extension: true "
2029 " } "
2030 " positive_int_value: 1234 "
2031 " } "
2032 " uninterpreted_option { "
2033 " name { "
2034 " name_part: \"optimize_for\" "
2035 " is_extension: false "
2036 " } "
2037 " identifier_value: \"SPEED\" "
2038 " } "
2039 "}",
2040 &option_proto));
2041
2042 const FileDescriptor* file = BuildFile(option_proto);
2043 ASSERT_TRUE(file != NULL);
2044
2045 // Verify that no extension options were set, but they were left as
2046 // uninterpreted_options.
2047 vector<const FieldDescriptor*> fields;
2048 file->options().GetReflection()->ListFields(file->options(), &fields);
2049 ASSERT_EQ(2, fields.size());
2050 EXPECT_TRUE(file->options().has_optimize_for());
2051 EXPECT_EQ(2, file->options().uninterpreted_option_size());
2052 }
2053
TEST_P(AllowUnknownDependenciesTest,UndeclaredDependencyTriggersBuildOfDependency)2054 TEST_P(AllowUnknownDependenciesTest,
2055 UndeclaredDependencyTriggersBuildOfDependency) {
2056 // Crazy case: suppose foo.proto refers to a symbol without declaring the
2057 // dependency that finds it. In the event that the pool is backed by a
2058 // DescriptorDatabase, the pool will attempt to find the symbol in the
2059 // database. If successful, it will build the undeclared dependency to verify
2060 // that the file does indeed contain the symbol. If that file fails to build,
2061 // then its descriptors must be rolled back. However, we still want foo.proto
2062 // to build successfully, since we are allowing unknown dependencies.
2063
2064 FileDescriptorProto undeclared_dep_proto;
2065 // We make this file fail to build by giving it two fields with tag 1.
2066 ASSERT_TRUE(TextFormat::ParseFromString(
2067 "name: \"invalid_file_as_undeclared_dep.proto\" "
2068 "package: \"undeclared\" "
2069 "message_type: { "
2070 " name: \"Quux\" "
2071 " field { "
2072 " name:'qux' number:1 label:LABEL_OPTIONAL type: TYPE_INT32 "
2073 " }"
2074 " field { "
2075 " name:'quux' number:1 label:LABEL_OPTIONAL type: TYPE_INT64 "
2076 " }"
2077 "}",
2078 &undeclared_dep_proto));
2079 // We can't use the BuildFile() helper because we don't actually want to build
2080 // it into the descriptor pool in the fallback database case: it just needs to
2081 // be sitting in the database so that it gets built during the building of
2082 // test.proto below.
2083 switch (mode()) {
2084 case NO_DATABASE: {
2085 ASSERT_TRUE(pool_->BuildFile(undeclared_dep_proto) == NULL);
2086 break;
2087 }
2088 case FALLBACK_DATABASE: {
2089 ASSERT_TRUE(db_.Add(undeclared_dep_proto));
2090 }
2091 }
2092
2093 FileDescriptorProto test_proto;
2094 ASSERT_TRUE(TextFormat::ParseFromString(
2095 "name: \"test.proto\" "
2096 "message_type: { "
2097 " name: \"Corge\" "
2098 " field { "
2099 " name:'quux' number:1 label: LABEL_OPTIONAL "
2100 " type_name:'undeclared.Quux' type: TYPE_MESSAGE "
2101 " }"
2102 "}",
2103 &test_proto));
2104
2105 const FileDescriptor* file = BuildFile(test_proto);
2106 ASSERT_TRUE(file != NULL);
2107 GOOGLE_LOG(INFO) << file->DebugString();
2108
2109 EXPECT_EQ(0, file->dependency_count());
2110 ASSERT_EQ(1, file->message_type_count());
2111 const Descriptor* corge_desc = file->message_type(0);
2112 ASSERT_EQ("Corge", corge_desc->name());
2113 ASSERT_EQ(1, corge_desc->field_count());
2114
2115 const FieldDescriptor* quux_field = corge_desc->field(0);
2116 ASSERT_EQ(FieldDescriptor::TYPE_MESSAGE, quux_field->type());
2117 ASSERT_EQ("Quux", quux_field->message_type()->name());
2118 ASSERT_EQ("undeclared.Quux", quux_field->message_type()->full_name());
2119 EXPECT_EQ("undeclared.Quux.placeholder.proto",
2120 quux_field->message_type()->file()->name());
2121 // The place holder type should not be findable.
2122 ASSERT_TRUE(pool_->FindMessageTypeByName("undeclared.Quux") == NULL);
2123 }
2124
2125 INSTANTIATE_TEST_CASE_P(DatabaseSource,
2126 AllowUnknownDependenciesTest,
2127 testing::Values(NO_DATABASE, FALLBACK_DATABASE));
2128
2129 // ===================================================================
2130
TEST(CustomOptions,OptionLocations)2131 TEST(CustomOptions, OptionLocations) {
2132 const Descriptor* message =
2133 protobuf_unittest::TestMessageWithCustomOptions::descriptor();
2134 const FileDescriptor* file = message->file();
2135 const FieldDescriptor* field = message->FindFieldByName("field1");
2136 const EnumDescriptor* enm = message->FindEnumTypeByName("AnEnum");
2137 // TODO(benjy): Support EnumValue options, once the compiler does.
2138 const ServiceDescriptor* service =
2139 file->FindServiceByName("TestServiceWithCustomOptions");
2140 const MethodDescriptor* method = service->FindMethodByName("Foo");
2141
2142 EXPECT_EQ(GOOGLE_LONGLONG(9876543210),
2143 file->options().GetExtension(protobuf_unittest::file_opt1));
2144 EXPECT_EQ(-56,
2145 message->options().GetExtension(protobuf_unittest::message_opt1));
2146 EXPECT_EQ(GOOGLE_LONGLONG(8765432109),
2147 field->options().GetExtension(protobuf_unittest::field_opt1));
2148 EXPECT_EQ(42, // Check that we get the default for an option we don't set.
2149 field->options().GetExtension(protobuf_unittest::field_opt2));
2150 EXPECT_EQ(-789,
2151 enm->options().GetExtension(protobuf_unittest::enum_opt1));
2152 EXPECT_EQ(123,
2153 enm->value(1)->options().GetExtension(
2154 protobuf_unittest::enum_value_opt1));
2155 EXPECT_EQ(GOOGLE_LONGLONG(-9876543210),
2156 service->options().GetExtension(protobuf_unittest::service_opt1));
2157 EXPECT_EQ(protobuf_unittest::METHODOPT1_VAL2,
2158 method->options().GetExtension(protobuf_unittest::method_opt1));
2159
2160 // See that the regular options went through unscathed.
2161 EXPECT_TRUE(message->options().has_message_set_wire_format());
2162 EXPECT_EQ(FieldOptions::CORD, field->options().ctype());
2163 }
2164
TEST(CustomOptions,OptionTypes)2165 TEST(CustomOptions, OptionTypes) {
2166 const MessageOptions* options = NULL;
2167
2168 options =
2169 &protobuf_unittest::CustomOptionMinIntegerValues::descriptor()->options();
2170 EXPECT_FALSE( options->GetExtension(protobuf_unittest::bool_opt));
2171 EXPECT_EQ(kint32min, options->GetExtension(protobuf_unittest::int32_opt));
2172 EXPECT_EQ(kint64min, options->GetExtension(protobuf_unittest::int64_opt));
2173 EXPECT_EQ(0 , options->GetExtension(protobuf_unittest::uint32_opt));
2174 EXPECT_EQ(0 , options->GetExtension(protobuf_unittest::uint64_opt));
2175 EXPECT_EQ(kint32min, options->GetExtension(protobuf_unittest::sint32_opt));
2176 EXPECT_EQ(kint64min, options->GetExtension(protobuf_unittest::sint64_opt));
2177 EXPECT_EQ(0 , options->GetExtension(protobuf_unittest::fixed32_opt));
2178 EXPECT_EQ(0 , options->GetExtension(protobuf_unittest::fixed64_opt));
2179 EXPECT_EQ(kint32min, options->GetExtension(protobuf_unittest::sfixed32_opt));
2180 EXPECT_EQ(kint64min, options->GetExtension(protobuf_unittest::sfixed64_opt));
2181
2182 options =
2183 &protobuf_unittest::CustomOptionMaxIntegerValues::descriptor()->options();
2184 EXPECT_TRUE( options->GetExtension(protobuf_unittest::bool_opt));
2185 EXPECT_EQ(kint32max , options->GetExtension(protobuf_unittest::int32_opt));
2186 EXPECT_EQ(kint64max , options->GetExtension(protobuf_unittest::int64_opt));
2187 EXPECT_EQ(kuint32max, options->GetExtension(protobuf_unittest::uint32_opt));
2188 EXPECT_EQ(kuint64max, options->GetExtension(protobuf_unittest::uint64_opt));
2189 EXPECT_EQ(kint32max , options->GetExtension(protobuf_unittest::sint32_opt));
2190 EXPECT_EQ(kint64max , options->GetExtension(protobuf_unittest::sint64_opt));
2191 EXPECT_EQ(kuint32max, options->GetExtension(protobuf_unittest::fixed32_opt));
2192 EXPECT_EQ(kuint64max, options->GetExtension(protobuf_unittest::fixed64_opt));
2193 EXPECT_EQ(kint32max , options->GetExtension(protobuf_unittest::sfixed32_opt));
2194 EXPECT_EQ(kint64max , options->GetExtension(protobuf_unittest::sfixed64_opt));
2195
2196 options =
2197 &protobuf_unittest::CustomOptionOtherValues::descriptor()->options();
2198 EXPECT_EQ(-100, options->GetExtension(protobuf_unittest::int32_opt));
2199 EXPECT_FLOAT_EQ(12.3456789,
2200 options->GetExtension(protobuf_unittest::float_opt));
2201 EXPECT_DOUBLE_EQ(1.234567890123456789,
2202 options->GetExtension(protobuf_unittest::double_opt));
2203 EXPECT_EQ("Hello, \"World\"",
2204 options->GetExtension(protobuf_unittest::string_opt));
2205
2206 EXPECT_EQ(string("Hello\0World", 11),
2207 options->GetExtension(protobuf_unittest::bytes_opt));
2208
2209 EXPECT_EQ(protobuf_unittest::DummyMessageContainingEnum::TEST_OPTION_ENUM_TYPE2,
2210 options->GetExtension(protobuf_unittest::enum_opt));
2211
2212 options =
2213 &protobuf_unittest::SettingRealsFromPositiveInts::descriptor()->options();
2214 EXPECT_FLOAT_EQ(12, options->GetExtension(protobuf_unittest::float_opt));
2215 EXPECT_DOUBLE_EQ(154, options->GetExtension(protobuf_unittest::double_opt));
2216
2217 options =
2218 &protobuf_unittest::SettingRealsFromNegativeInts::descriptor()->options();
2219 EXPECT_FLOAT_EQ(-12, options->GetExtension(protobuf_unittest::float_opt));
2220 EXPECT_DOUBLE_EQ(-154, options->GetExtension(protobuf_unittest::double_opt));
2221 }
2222
TEST(CustomOptions,ComplexExtensionOptions)2223 TEST(CustomOptions, ComplexExtensionOptions) {
2224 const MessageOptions* options =
2225 &protobuf_unittest::VariousComplexOptions::descriptor()->options();
2226 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt1).foo(), 42);
2227 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt1).
2228 GetExtension(protobuf_unittest::quux), 324);
2229 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt1).
2230 GetExtension(protobuf_unittest::corge).qux(), 876);
2231 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2).baz(), 987);
2232 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2).
2233 GetExtension(protobuf_unittest::grault), 654);
2234 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2).bar().foo(),
2235 743);
2236 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2).bar().
2237 GetExtension(protobuf_unittest::quux), 1999);
2238 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2).bar().
2239 GetExtension(protobuf_unittest::corge).qux(), 2008);
2240 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2).
2241 GetExtension(protobuf_unittest::garply).foo(), 741);
2242 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2).
2243 GetExtension(protobuf_unittest::garply).
2244 GetExtension(protobuf_unittest::quux), 1998);
2245 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2).
2246 GetExtension(protobuf_unittest::garply).
2247 GetExtension(protobuf_unittest::corge).qux(), 2121);
2248 EXPECT_EQ(options->GetExtension(
2249 protobuf_unittest::ComplexOptionType2::ComplexOptionType4::complex_opt4).
2250 waldo(), 1971);
2251 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2).
2252 fred().waldo(), 321);
2253 EXPECT_EQ(9, options->GetExtension(protobuf_unittest::complex_opt3).qux());
2254 EXPECT_EQ(22, options->GetExtension(protobuf_unittest::complex_opt3).
2255 complexoptiontype5().plugh());
2256 EXPECT_EQ(24, options->GetExtension(protobuf_unittest::complexopt6).xyzzy());
2257 }
2258
TEST(CustomOptions,OptionsFromOtherFile)2259 TEST(CustomOptions, OptionsFromOtherFile) {
2260 // Test that to use a custom option, we only need to import the file
2261 // defining the option; we do not also have to import descriptor.proto.
2262 DescriptorPool pool;
2263
2264 FileDescriptorProto file_proto;
2265 FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto);
2266 ASSERT_TRUE(pool.BuildFile(file_proto) != NULL);
2267
2268 protobuf_unittest::TestMessageWithCustomOptions::descriptor()
2269 ->file()->CopyTo(&file_proto);
2270 ASSERT_TRUE(pool.BuildFile(file_proto) != NULL);
2271
2272 ASSERT_TRUE(TextFormat::ParseFromString(
2273 "name: \"custom_options_import.proto\" "
2274 "package: \"protobuf_unittest\" "
2275 "dependency: \"google/protobuf/unittest_custom_options.proto\" "
2276 "options { "
2277 " uninterpreted_option { "
2278 " name { "
2279 " name_part: \"file_opt1\" "
2280 " is_extension: true "
2281 " } "
2282 " positive_int_value: 1234 "
2283 " } "
2284 // Test a non-extension option too. (At one point this failed due to a
2285 // bug.)
2286 " uninterpreted_option { "
2287 " name { "
2288 " name_part: \"java_package\" "
2289 " is_extension: false "
2290 " } "
2291 " string_value: \"foo\" "
2292 " } "
2293 // Test that enum-typed options still work too. (At one point this also
2294 // failed due to a bug.)
2295 " uninterpreted_option { "
2296 " name { "
2297 " name_part: \"optimize_for\" "
2298 " is_extension: false "
2299 " } "
2300 " identifier_value: \"SPEED\" "
2301 " } "
2302 "}"
2303 ,
2304 &file_proto));
2305
2306 const FileDescriptor* file = pool.BuildFile(file_proto);
2307 ASSERT_TRUE(file != NULL);
2308 EXPECT_EQ(1234, file->options().GetExtension(protobuf_unittest::file_opt1));
2309 EXPECT_TRUE(file->options().has_java_package());
2310 EXPECT_EQ("foo", file->options().java_package());
2311 EXPECT_TRUE(file->options().has_optimize_for());
2312 EXPECT_EQ(FileOptions::SPEED, file->options().optimize_for());
2313 }
2314
TEST(CustomOptions,MessageOptionThreeFieldsSet)2315 TEST(CustomOptions, MessageOptionThreeFieldsSet) {
2316 // This tests a bug which previously existed in custom options parsing. The
2317 // bug occurred when you defined a custom option with message type and then
2318 // set three fields of that option on a single definition (see the example
2319 // below). The bug is a bit hard to explain, so check the change history if
2320 // you want to know more.
2321 DescriptorPool pool;
2322
2323 FileDescriptorProto file_proto;
2324 FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto);
2325 ASSERT_TRUE(pool.BuildFile(file_proto) != NULL);
2326
2327 protobuf_unittest::TestMessageWithCustomOptions::descriptor()
2328 ->file()->CopyTo(&file_proto);
2329 ASSERT_TRUE(pool.BuildFile(file_proto) != NULL);
2330
2331 // The following represents the definition:
2332 //
2333 // import "google/protobuf/unittest_custom_options.proto"
2334 // package protobuf_unittest;
2335 // message Foo {
2336 // option (complex_opt1).foo = 1234;
2337 // option (complex_opt1).foo2 = 1234;
2338 // option (complex_opt1).foo3 = 1234;
2339 // }
2340 ASSERT_TRUE(TextFormat::ParseFromString(
2341 "name: \"custom_options_import.proto\" "
2342 "package: \"protobuf_unittest\" "
2343 "dependency: \"google/protobuf/unittest_custom_options.proto\" "
2344 "message_type { "
2345 " name: \"Foo\" "
2346 " options { "
2347 " uninterpreted_option { "
2348 " name { "
2349 " name_part: \"complex_opt1\" "
2350 " is_extension: true "
2351 " } "
2352 " name { "
2353 " name_part: \"foo\" "
2354 " is_extension: false "
2355 " } "
2356 " positive_int_value: 1234 "
2357 " } "
2358 " uninterpreted_option { "
2359 " name { "
2360 " name_part: \"complex_opt1\" "
2361 " is_extension: true "
2362 " } "
2363 " name { "
2364 " name_part: \"foo2\" "
2365 " is_extension: false "
2366 " } "
2367 " positive_int_value: 1234 "
2368 " } "
2369 " uninterpreted_option { "
2370 " name { "
2371 " name_part: \"complex_opt1\" "
2372 " is_extension: true "
2373 " } "
2374 " name { "
2375 " name_part: \"foo3\" "
2376 " is_extension: false "
2377 " } "
2378 " positive_int_value: 1234 "
2379 " } "
2380 " } "
2381 "}",
2382 &file_proto));
2383
2384 const FileDescriptor* file = pool.BuildFile(file_proto);
2385 ASSERT_TRUE(file != NULL);
2386 ASSERT_EQ(1, file->message_type_count());
2387
2388 const MessageOptions& options = file->message_type(0)->options();
2389 EXPECT_EQ(1234, options.GetExtension(protobuf_unittest::complex_opt1).foo());
2390 }
2391
2392 // Check that aggregate options were parsed and saved correctly in
2393 // the appropriate descriptors.
TEST(CustomOptions,AggregateOptions)2394 TEST(CustomOptions, AggregateOptions) {
2395 const Descriptor* msg = protobuf_unittest::AggregateMessage::descriptor();
2396 const FileDescriptor* file = msg->file();
2397 const FieldDescriptor* field = msg->FindFieldByName("fieldname");
2398 const EnumDescriptor* enumd = file->FindEnumTypeByName("AggregateEnum");
2399 const EnumValueDescriptor* enumv = enumd->FindValueByName("VALUE");
2400 const ServiceDescriptor* service = file->FindServiceByName(
2401 "AggregateService");
2402 const MethodDescriptor* method = service->FindMethodByName("Method");
2403
2404 // Tests for the different types of data embedded in fileopt
2405 const protobuf_unittest::Aggregate& file_options =
2406 file->options().GetExtension(protobuf_unittest::fileopt);
2407 EXPECT_EQ(100, file_options.i());
2408 EXPECT_EQ("FileAnnotation", file_options.s());
2409 EXPECT_EQ("NestedFileAnnotation", file_options.sub().s());
2410 EXPECT_EQ("FileExtensionAnnotation",
2411 file_options.file().GetExtension(protobuf_unittest::fileopt).s());
2412 EXPECT_EQ("EmbeddedMessageSetElement",
2413 file_options.mset().GetExtension(
2414 protobuf_unittest::AggregateMessageSetElement
2415 ::message_set_extension).s());
2416
2417 // Simple tests for all the other types of annotations
2418 EXPECT_EQ("MessageAnnotation",
2419 msg->options().GetExtension(protobuf_unittest::msgopt).s());
2420 EXPECT_EQ("FieldAnnotation",
2421 field->options().GetExtension(protobuf_unittest::fieldopt).s());
2422 EXPECT_EQ("EnumAnnotation",
2423 enumd->options().GetExtension(protobuf_unittest::enumopt).s());
2424 EXPECT_EQ("EnumValueAnnotation",
2425 enumv->options().GetExtension(protobuf_unittest::enumvalopt).s());
2426 EXPECT_EQ("ServiceAnnotation",
2427 service->options().GetExtension(protobuf_unittest::serviceopt).s());
2428 EXPECT_EQ("MethodAnnotation",
2429 method->options().GetExtension(protobuf_unittest::methodopt).s());
2430 }
2431
2432 // ===================================================================
2433
2434 // The tests below trigger every unique call to AddError() in descriptor.cc,
2435 // in the order in which they appear in that file. I'm using TextFormat here
2436 // to specify the input descriptors because building them using code would
2437 // be too bulky.
2438
2439 class MockErrorCollector : public DescriptorPool::ErrorCollector {
2440 public:
MockErrorCollector()2441 MockErrorCollector() {}
~MockErrorCollector()2442 ~MockErrorCollector() {}
2443
2444 string text_;
2445
2446 // implements ErrorCollector ---------------------------------------
AddError(const string & filename,const string & element_name,const Message * descriptor,ErrorLocation location,const string & message)2447 void AddError(const string& filename,
2448 const string& element_name, const Message* descriptor,
2449 ErrorLocation location, const string& message) {
2450 const char* location_name = NULL;
2451 switch (location) {
2452 case NAME : location_name = "NAME" ; break;
2453 case NUMBER : location_name = "NUMBER" ; break;
2454 case TYPE : location_name = "TYPE" ; break;
2455 case EXTENDEE : location_name = "EXTENDEE" ; break;
2456 case DEFAULT_VALUE: location_name = "DEFAULT_VALUE"; break;
2457 case OPTION_NAME : location_name = "OPTION_NAME" ; break;
2458 case OPTION_VALUE : location_name = "OPTION_VALUE" ; break;
2459 case INPUT_TYPE : location_name = "INPUT_TYPE" ; break;
2460 case OUTPUT_TYPE : location_name = "OUTPUT_TYPE" ; break;
2461 case OTHER : location_name = "OTHER" ; break;
2462 }
2463
2464 strings::SubstituteAndAppend(
2465 &text_, "$0: $1: $2: $3\n",
2466 filename, element_name, location_name, message);
2467 }
2468 };
2469
2470 class ValidationErrorTest : public testing::Test {
2471 protected:
2472 // Parse file_text as a FileDescriptorProto in text format and add it
2473 // to the DescriptorPool. Expect no errors.
BuildFile(const string & file_text)2474 void BuildFile(const string& file_text) {
2475 FileDescriptorProto file_proto;
2476 ASSERT_TRUE(TextFormat::ParseFromString(file_text, &file_proto));
2477 ASSERT_TRUE(pool_.BuildFile(file_proto) != NULL);
2478 }
2479
2480 // Parse file_text as a FileDescriptorProto in text format and add it
2481 // to the DescriptorPool. Expect errors to be produced which match the
2482 // given error text.
BuildFileWithErrors(const string & file_text,const string & expected_errors)2483 void BuildFileWithErrors(const string& file_text,
2484 const string& expected_errors) {
2485 FileDescriptorProto file_proto;
2486 ASSERT_TRUE(TextFormat::ParseFromString(file_text, &file_proto));
2487
2488 MockErrorCollector error_collector;
2489 EXPECT_TRUE(
2490 pool_.BuildFileCollectingErrors(file_proto, &error_collector) == NULL);
2491 EXPECT_EQ(expected_errors, error_collector.text_);
2492 }
2493
2494 // Builds some already-parsed file in our test pool.
BuildFileInTestPool(const FileDescriptor * file)2495 void BuildFileInTestPool(const FileDescriptor* file) {
2496 FileDescriptorProto file_proto;
2497 file->CopyTo(&file_proto);
2498 ASSERT_TRUE(pool_.BuildFile(file_proto) != NULL);
2499 }
2500
2501 // Build descriptor.proto in our test pool. This allows us to extend it in
2502 // the test pool, so we can test custom options.
BuildDescriptorMessagesInTestPool()2503 void BuildDescriptorMessagesInTestPool() {
2504 BuildFileInTestPool(DescriptorProto::descriptor()->file());
2505 }
2506
2507 DescriptorPool pool_;
2508 };
2509
TEST_F(ValidationErrorTest,AlreadyDefined)2510 TEST_F(ValidationErrorTest, AlreadyDefined) {
2511 BuildFileWithErrors(
2512 "name: \"foo.proto\" "
2513 "message_type { name: \"Foo\" }"
2514 "message_type { name: \"Foo\" }",
2515
2516 "foo.proto: Foo: NAME: \"Foo\" is already defined.\n");
2517 }
2518
TEST_F(ValidationErrorTest,AlreadyDefinedInPackage)2519 TEST_F(ValidationErrorTest, AlreadyDefinedInPackage) {
2520 BuildFileWithErrors(
2521 "name: \"foo.proto\" "
2522 "package: \"foo.bar\" "
2523 "message_type { name: \"Foo\" }"
2524 "message_type { name: \"Foo\" }",
2525
2526 "foo.proto: foo.bar.Foo: NAME: \"Foo\" is already defined in "
2527 "\"foo.bar\".\n");
2528 }
2529
TEST_F(ValidationErrorTest,AlreadyDefinedInOtherFile)2530 TEST_F(ValidationErrorTest, AlreadyDefinedInOtherFile) {
2531 BuildFile(
2532 "name: \"foo.proto\" "
2533 "message_type { name: \"Foo\" }");
2534
2535 BuildFileWithErrors(
2536 "name: \"bar.proto\" "
2537 "message_type { name: \"Foo\" }",
2538
2539 "bar.proto: Foo: NAME: \"Foo\" is already defined in file "
2540 "\"foo.proto\".\n");
2541 }
2542
TEST_F(ValidationErrorTest,PackageAlreadyDefined)2543 TEST_F(ValidationErrorTest, PackageAlreadyDefined) {
2544 BuildFile(
2545 "name: \"foo.proto\" "
2546 "message_type { name: \"foo\" }");
2547 BuildFileWithErrors(
2548 "name: \"bar.proto\" "
2549 "package: \"foo.bar\"",
2550
2551 "bar.proto: foo: NAME: \"foo\" is already defined (as something other "
2552 "than a package) in file \"foo.proto\".\n");
2553 }
2554
TEST_F(ValidationErrorTest,EnumValueAlreadyDefinedInParent)2555 TEST_F(ValidationErrorTest, EnumValueAlreadyDefinedInParent) {
2556 BuildFileWithErrors(
2557 "name: \"foo.proto\" "
2558 "enum_type { name: \"Foo\" value { name: \"FOO\" number: 1 } } "
2559 "enum_type { name: \"Bar\" value { name: \"FOO\" number: 1 } } ",
2560
2561 "foo.proto: FOO: NAME: \"FOO\" is already defined.\n"
2562 "foo.proto: FOO: NAME: Note that enum values use C++ scoping rules, "
2563 "meaning that enum values are siblings of their type, not children of "
2564 "it. Therefore, \"FOO\" must be unique within the global scope, not "
2565 "just within \"Bar\".\n");
2566 }
2567
TEST_F(ValidationErrorTest,EnumValueAlreadyDefinedInParentNonGlobal)2568 TEST_F(ValidationErrorTest, EnumValueAlreadyDefinedInParentNonGlobal) {
2569 BuildFileWithErrors(
2570 "name: \"foo.proto\" "
2571 "package: \"pkg\" "
2572 "enum_type { name: \"Foo\" value { name: \"FOO\" number: 1 } } "
2573 "enum_type { name: \"Bar\" value { name: \"FOO\" number: 1 } } ",
2574
2575 "foo.proto: pkg.FOO: NAME: \"FOO\" is already defined in \"pkg\".\n"
2576 "foo.proto: pkg.FOO: NAME: Note that enum values use C++ scoping rules, "
2577 "meaning that enum values are siblings of their type, not children of "
2578 "it. Therefore, \"FOO\" must be unique within \"pkg\", not just within "
2579 "\"Bar\".\n");
2580 }
2581
TEST_F(ValidationErrorTest,MissingName)2582 TEST_F(ValidationErrorTest, MissingName) {
2583 BuildFileWithErrors(
2584 "name: \"foo.proto\" "
2585 "message_type { }",
2586
2587 "foo.proto: : NAME: Missing name.\n");
2588 }
2589
TEST_F(ValidationErrorTest,InvalidName)2590 TEST_F(ValidationErrorTest, InvalidName) {
2591 BuildFileWithErrors(
2592 "name: \"foo.proto\" "
2593 "message_type { name: \"$\" }",
2594
2595 "foo.proto: $: NAME: \"$\" is not a valid identifier.\n");
2596 }
2597
TEST_F(ValidationErrorTest,InvalidPackageName)2598 TEST_F(ValidationErrorTest, InvalidPackageName) {
2599 BuildFileWithErrors(
2600 "name: \"foo.proto\" "
2601 "package: \"foo.$\"",
2602
2603 "foo.proto: foo.$: NAME: \"$\" is not a valid identifier.\n");
2604 }
2605
TEST_F(ValidationErrorTest,MissingFileName)2606 TEST_F(ValidationErrorTest, MissingFileName) {
2607 BuildFileWithErrors(
2608 "",
2609
2610 ": : OTHER: Missing field: FileDescriptorProto.name.\n");
2611 }
2612
TEST_F(ValidationErrorTest,DupeDependency)2613 TEST_F(ValidationErrorTest, DupeDependency) {
2614 BuildFile("name: \"foo.proto\"");
2615 BuildFileWithErrors(
2616 "name: \"bar.proto\" "
2617 "dependency: \"foo.proto\" "
2618 "dependency: \"foo.proto\" ",
2619
2620 "bar.proto: bar.proto: OTHER: Import \"foo.proto\" was listed twice.\n");
2621 }
2622
TEST_F(ValidationErrorTest,UnknownDependency)2623 TEST_F(ValidationErrorTest, UnknownDependency) {
2624 BuildFileWithErrors(
2625 "name: \"bar.proto\" "
2626 "dependency: \"foo.proto\" ",
2627
2628 "bar.proto: bar.proto: OTHER: Import \"foo.proto\" has not been loaded.\n");
2629 }
2630
TEST_F(ValidationErrorTest,InvalidPublicDependencyIndex)2631 TEST_F(ValidationErrorTest, InvalidPublicDependencyIndex) {
2632 BuildFile("name: \"foo.proto\"");
2633 BuildFileWithErrors(
2634 "name: \"bar.proto\" "
2635 "dependency: \"foo.proto\" "
2636 "public_dependency: 1",
2637 "bar.proto: bar.proto: OTHER: Invalid public dependency index.\n");
2638 }
2639
TEST_F(ValidationErrorTest,ForeignUnimportedPackageNoCrash)2640 TEST_F(ValidationErrorTest, ForeignUnimportedPackageNoCrash) {
2641 // Used to crash: If we depend on a non-existent file and then refer to a
2642 // package defined in a file that we didn't import, and that package is
2643 // nested within a parent package which this file is also in, and we don't
2644 // include that parent package in the name (i.e. we do a relative lookup)...
2645 // Yes, really.
2646 BuildFile(
2647 "name: 'foo.proto' "
2648 "package: 'outer.foo' ");
2649 BuildFileWithErrors(
2650 "name: 'bar.proto' "
2651 "dependency: 'baz.proto' "
2652 "package: 'outer.bar' "
2653 "message_type { "
2654 " name: 'Bar' "
2655 " field { name:'bar' number:1 label:LABEL_OPTIONAL type_name:'foo.Foo' }"
2656 "}",
2657
2658 "bar.proto: bar.proto: OTHER: Import \"baz.proto\" has not been loaded.\n"
2659 "bar.proto: outer.bar.Bar.bar: TYPE: \"outer.foo\" seems to be defined in "
2660 "\"foo.proto\", which is not imported by \"bar.proto\". To use it here, "
2661 "please add the necessary import.\n");
2662 }
2663
TEST_F(ValidationErrorTest,DupeFile)2664 TEST_F(ValidationErrorTest, DupeFile) {
2665 BuildFile(
2666 "name: \"foo.proto\" "
2667 "message_type { name: \"Foo\" }");
2668 // Note: We should *not* get redundant errors about "Foo" already being
2669 // defined.
2670 BuildFileWithErrors(
2671 "name: \"foo.proto\" "
2672 "message_type { name: \"Foo\" } "
2673 // Add another type so that the files aren't identical (in which case there
2674 // would be no error).
2675 "enum_type { name: \"Bar\" }",
2676
2677 "foo.proto: foo.proto: OTHER: A file with this name is already in the "
2678 "pool.\n");
2679 }
2680
TEST_F(ValidationErrorTest,FieldInExtensionRange)2681 TEST_F(ValidationErrorTest, FieldInExtensionRange) {
2682 BuildFileWithErrors(
2683 "name: \"foo.proto\" "
2684 "message_type {"
2685 " name: \"Foo\""
2686 " field { name: \"foo\" number: 9 label:LABEL_OPTIONAL type:TYPE_INT32 }"
2687 " field { name: \"bar\" number: 10 label:LABEL_OPTIONAL type:TYPE_INT32 }"
2688 " field { name: \"baz\" number: 19 label:LABEL_OPTIONAL type:TYPE_INT32 }"
2689 " field { name: \"qux\" number: 20 label:LABEL_OPTIONAL type:TYPE_INT32 }"
2690 " extension_range { start: 10 end: 20 }"
2691 "}",
2692
2693 "foo.proto: Foo.bar: NUMBER: Extension range 10 to 19 includes field "
2694 "\"bar\" (10).\n"
2695 "foo.proto: Foo.baz: NUMBER: Extension range 10 to 19 includes field "
2696 "\"baz\" (19).\n");
2697 }
2698
TEST_F(ValidationErrorTest,OverlappingExtensionRanges)2699 TEST_F(ValidationErrorTest, OverlappingExtensionRanges) {
2700 BuildFileWithErrors(
2701 "name: \"foo.proto\" "
2702 "message_type {"
2703 " name: \"Foo\""
2704 " extension_range { start: 10 end: 20 }"
2705 " extension_range { start: 20 end: 30 }"
2706 " extension_range { start: 19 end: 21 }"
2707 "}",
2708
2709 "foo.proto: Foo: NUMBER: Extension range 19 to 20 overlaps with "
2710 "already-defined range 10 to 19.\n"
2711 "foo.proto: Foo: NUMBER: Extension range 19 to 20 overlaps with "
2712 "already-defined range 20 to 29.\n");
2713 }
2714
TEST_F(ValidationErrorTest,InvalidDefaults)2715 TEST_F(ValidationErrorTest, InvalidDefaults) {
2716 BuildFileWithErrors(
2717 "name: \"foo.proto\" "
2718 "message_type {"
2719 " name: \"Foo\""
2720
2721 // Invalid number.
2722 " field { name: \"foo\" number: 1 label: LABEL_OPTIONAL type: TYPE_INT32"
2723 " default_value: \"abc\" }"
2724
2725 // Empty default value.
2726 " field { name: \"bar\" number: 2 label: LABEL_OPTIONAL type: TYPE_INT32"
2727 " default_value: \"\" }"
2728
2729 // Invalid boolean.
2730 " field { name: \"baz\" number: 3 label: LABEL_OPTIONAL type: TYPE_BOOL"
2731 " default_value: \"abc\" }"
2732
2733 // Messages can't have defaults.
2734 " field { name: \"qux\" number: 4 label: LABEL_OPTIONAL type: TYPE_MESSAGE"
2735 " default_value: \"abc\" type_name: \"Foo\" }"
2736
2737 // Same thing, but we don't know that this field has message type until
2738 // we look up the type name.
2739 " field { name: \"quux\" number: 5 label: LABEL_OPTIONAL"
2740 " default_value: \"abc\" type_name: \"Foo\" }"
2741
2742 // Repeateds can't have defaults.
2743 " field { name: \"corge\" number: 6 label: LABEL_REPEATED type: TYPE_INT32"
2744 " default_value: \"1\" }"
2745 "}",
2746
2747 "foo.proto: Foo.foo: DEFAULT_VALUE: Couldn't parse default value.\n"
2748 "foo.proto: Foo.bar: DEFAULT_VALUE: Couldn't parse default value.\n"
2749 "foo.proto: Foo.baz: DEFAULT_VALUE: Boolean default must be true or "
2750 "false.\n"
2751 "foo.proto: Foo.qux: DEFAULT_VALUE: Messages can't have default values.\n"
2752 "foo.proto: Foo.corge: DEFAULT_VALUE: Repeated fields can't have default "
2753 "values.\n"
2754 // This ends up being reported later because the error is detected at
2755 // cross-linking time.
2756 "foo.proto: Foo.quux: DEFAULT_VALUE: Messages can't have default "
2757 "values.\n");
2758 }
2759
TEST_F(ValidationErrorTest,NegativeFieldNumber)2760 TEST_F(ValidationErrorTest, NegativeFieldNumber) {
2761 BuildFileWithErrors(
2762 "name: \"foo.proto\" "
2763 "message_type {"
2764 " name: \"Foo\""
2765 " field { name: \"foo\" number: -1 label:LABEL_OPTIONAL type:TYPE_INT32 }"
2766 "}",
2767
2768 "foo.proto: Foo.foo: NUMBER: Field numbers must be positive integers.\n");
2769 }
2770
TEST_F(ValidationErrorTest,HugeFieldNumber)2771 TEST_F(ValidationErrorTest, HugeFieldNumber) {
2772 BuildFileWithErrors(
2773 "name: \"foo.proto\" "
2774 "message_type {"
2775 " name: \"Foo\""
2776 " field { name: \"foo\" number: 0x70000000 "
2777 " label:LABEL_OPTIONAL type:TYPE_INT32 }"
2778 "}",
2779
2780 "foo.proto: Foo.foo: NUMBER: Field numbers cannot be greater than "
2781 "536870911.\n");
2782 }
2783
TEST_F(ValidationErrorTest,ReservedFieldNumber)2784 TEST_F(ValidationErrorTest, ReservedFieldNumber) {
2785 BuildFileWithErrors(
2786 "name: \"foo.proto\" "
2787 "message_type {"
2788 " name: \"Foo\""
2789 " field {name:\"foo\" number: 18999 label:LABEL_OPTIONAL type:TYPE_INT32 }"
2790 " field {name:\"bar\" number: 19000 label:LABEL_OPTIONAL type:TYPE_INT32 }"
2791 " field {name:\"baz\" number: 19999 label:LABEL_OPTIONAL type:TYPE_INT32 }"
2792 " field {name:\"qux\" number: 20000 label:LABEL_OPTIONAL type:TYPE_INT32 }"
2793 "}",
2794
2795 "foo.proto: Foo.bar: NUMBER: Field numbers 19000 through 19999 are "
2796 "reserved for the protocol buffer library implementation.\n"
2797 "foo.proto: Foo.baz: NUMBER: Field numbers 19000 through 19999 are "
2798 "reserved for the protocol buffer library implementation.\n");
2799 }
2800
TEST_F(ValidationErrorTest,ExtensionMissingExtendee)2801 TEST_F(ValidationErrorTest, ExtensionMissingExtendee) {
2802 BuildFileWithErrors(
2803 "name: \"foo.proto\" "
2804 "message_type {"
2805 " name: \"Foo\""
2806 " extension { name: \"foo\" number: 1 label: LABEL_OPTIONAL"
2807 " type_name: \"Foo\" }"
2808 "}",
2809
2810 "foo.proto: Foo.foo: EXTENDEE: FieldDescriptorProto.extendee not set for "
2811 "extension field.\n");
2812 }
2813
TEST_F(ValidationErrorTest,NonExtensionWithExtendee)2814 TEST_F(ValidationErrorTest, NonExtensionWithExtendee) {
2815 BuildFileWithErrors(
2816 "name: \"foo.proto\" "
2817 "message_type {"
2818 " name: \"Bar\""
2819 " extension_range { start: 1 end: 2 }"
2820 "}"
2821 "message_type {"
2822 " name: \"Foo\""
2823 " field { name: \"foo\" number: 1 label: LABEL_OPTIONAL"
2824 " type_name: \"Foo\" extendee: \"Bar\" }"
2825 "}",
2826
2827 "foo.proto: Foo.foo: EXTENDEE: FieldDescriptorProto.extendee set for "
2828 "non-extension field.\n");
2829 }
2830
TEST_F(ValidationErrorTest,FieldNumberConflict)2831 TEST_F(ValidationErrorTest, FieldNumberConflict) {
2832 BuildFileWithErrors(
2833 "name: \"foo.proto\" "
2834 "message_type {"
2835 " name: \"Foo\""
2836 " field { name: \"foo\" number: 1 label:LABEL_OPTIONAL type:TYPE_INT32 }"
2837 " field { name: \"bar\" number: 1 label:LABEL_OPTIONAL type:TYPE_INT32 }"
2838 "}",
2839
2840 "foo.proto: Foo.bar: NUMBER: Field number 1 has already been used in "
2841 "\"Foo\" by field \"foo\".\n");
2842 }
2843
TEST_F(ValidationErrorTest,BadMessageSetExtensionType)2844 TEST_F(ValidationErrorTest, BadMessageSetExtensionType) {
2845 BuildFileWithErrors(
2846 "name: \"foo.proto\" "
2847 "message_type {"
2848 " name: \"MessageSet\""
2849 " options { message_set_wire_format: true }"
2850 " extension_range { start: 4 end: 5 }"
2851 "}"
2852 "message_type {"
2853 " name: \"Foo\""
2854 " extension { name:\"foo\" number:4 label:LABEL_OPTIONAL type:TYPE_INT32"
2855 " extendee: \"MessageSet\" }"
2856 "}",
2857
2858 "foo.proto: Foo.foo: TYPE: Extensions of MessageSets must be optional "
2859 "messages.\n");
2860 }
2861
TEST_F(ValidationErrorTest,BadMessageSetExtensionLabel)2862 TEST_F(ValidationErrorTest, BadMessageSetExtensionLabel) {
2863 BuildFileWithErrors(
2864 "name: \"foo.proto\" "
2865 "message_type {"
2866 " name: \"MessageSet\""
2867 " options { message_set_wire_format: true }"
2868 " extension_range { start: 4 end: 5 }"
2869 "}"
2870 "message_type {"
2871 " name: \"Foo\""
2872 " extension { name:\"foo\" number:4 label:LABEL_REPEATED type:TYPE_MESSAGE"
2873 " type_name: \"Foo\" extendee: \"MessageSet\" }"
2874 "}",
2875
2876 "foo.proto: Foo.foo: TYPE: Extensions of MessageSets must be optional "
2877 "messages.\n");
2878 }
2879
TEST_F(ValidationErrorTest,FieldInMessageSet)2880 TEST_F(ValidationErrorTest, FieldInMessageSet) {
2881 BuildFileWithErrors(
2882 "name: \"foo.proto\" "
2883 "message_type {"
2884 " name: \"Foo\""
2885 " options { message_set_wire_format: true }"
2886 " field { name: \"foo\" number: 1 label:LABEL_OPTIONAL type:TYPE_INT32 }"
2887 "}",
2888
2889 "foo.proto: Foo.foo: NAME: MessageSets cannot have fields, only "
2890 "extensions.\n");
2891 }
2892
TEST_F(ValidationErrorTest,NegativeExtensionRangeNumber)2893 TEST_F(ValidationErrorTest, NegativeExtensionRangeNumber) {
2894 BuildFileWithErrors(
2895 "name: \"foo.proto\" "
2896 "message_type {"
2897 " name: \"Foo\""
2898 " extension_range { start: -10 end: -1 }"
2899 "}",
2900
2901 "foo.proto: Foo: NUMBER: Extension numbers must be positive integers.\n");
2902 }
2903
TEST_F(ValidationErrorTest,HugeExtensionRangeNumber)2904 TEST_F(ValidationErrorTest, HugeExtensionRangeNumber) {
2905 BuildFileWithErrors(
2906 "name: \"foo.proto\" "
2907 "message_type {"
2908 " name: \"Foo\""
2909 " extension_range { start: 1 end: 0x70000000 }"
2910 "}",
2911
2912 "foo.proto: Foo: NUMBER: Extension numbers cannot be greater than "
2913 "536870911.\n");
2914 }
2915
TEST_F(ValidationErrorTest,ExtensionRangeEndBeforeStart)2916 TEST_F(ValidationErrorTest, ExtensionRangeEndBeforeStart) {
2917 BuildFileWithErrors(
2918 "name: \"foo.proto\" "
2919 "message_type {"
2920 " name: \"Foo\""
2921 " extension_range { start: 10 end: 10 }"
2922 " extension_range { start: 10 end: 5 }"
2923 "}",
2924
2925 "foo.proto: Foo: NUMBER: Extension range end number must be greater than "
2926 "start number.\n"
2927 "foo.proto: Foo: NUMBER: Extension range end number must be greater than "
2928 "start number.\n");
2929 }
2930
TEST_F(ValidationErrorTest,EmptyEnum)2931 TEST_F(ValidationErrorTest, EmptyEnum) {
2932 BuildFileWithErrors(
2933 "name: \"foo.proto\" "
2934 "enum_type { name: \"Foo\" }"
2935 // Also use the empty enum in a message to make sure there are no crashes
2936 // during validation (possible if the code attempts to derive a default
2937 // value for the field).
2938 "message_type {"
2939 " name: \"Bar\""
2940 " field { name: \"foo\" number: 1 label:LABEL_OPTIONAL type_name:\"Foo\" }"
2941 " field { name: \"bar\" number: 2 label:LABEL_OPTIONAL type_name:\"Foo\" "
2942 " default_value: \"NO_SUCH_VALUE\" }"
2943 "}",
2944
2945 "foo.proto: Foo: NAME: Enums must contain at least one value.\n"
2946 "foo.proto: Bar.bar: DEFAULT_VALUE: Enum type \"Foo\" has no value named "
2947 "\"NO_SUCH_VALUE\".\n");
2948 }
2949
TEST_F(ValidationErrorTest,UndefinedExtendee)2950 TEST_F(ValidationErrorTest, UndefinedExtendee) {
2951 BuildFileWithErrors(
2952 "name: \"foo.proto\" "
2953 "message_type {"
2954 " name: \"Foo\""
2955 " extension { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_INT32"
2956 " extendee: \"Bar\" }"
2957 "}",
2958
2959 "foo.proto: Foo.foo: EXTENDEE: \"Bar\" is not defined.\n");
2960 }
2961
TEST_F(ValidationErrorTest,NonMessageExtendee)2962 TEST_F(ValidationErrorTest, NonMessageExtendee) {
2963 BuildFileWithErrors(
2964 "name: \"foo.proto\" "
2965 "enum_type { name: \"Bar\" value { name:\"DUMMY\" number:0 } }"
2966 "message_type {"
2967 " name: \"Foo\""
2968 " extension { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_INT32"
2969 " extendee: \"Bar\" }"
2970 "}",
2971
2972 "foo.proto: Foo.foo: EXTENDEE: \"Bar\" is not a message type.\n");
2973 }
2974
TEST_F(ValidationErrorTest,NotAnExtensionNumber)2975 TEST_F(ValidationErrorTest, NotAnExtensionNumber) {
2976 BuildFileWithErrors(
2977 "name: \"foo.proto\" "
2978 "message_type {"
2979 " name: \"Bar\""
2980 "}"
2981 "message_type {"
2982 " name: \"Foo\""
2983 " extension { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_INT32"
2984 " extendee: \"Bar\" }"
2985 "}",
2986
2987 "foo.proto: Foo.foo: NUMBER: \"Bar\" does not declare 1 as an extension "
2988 "number.\n");
2989 }
2990
TEST_F(ValidationErrorTest,UndefinedFieldType)2991 TEST_F(ValidationErrorTest, UndefinedFieldType) {
2992 BuildFileWithErrors(
2993 "name: \"foo.proto\" "
2994 "message_type {"
2995 " name: \"Foo\""
2996 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
2997 "}",
2998
2999 "foo.proto: Foo.foo: TYPE: \"Bar\" is not defined.\n");
3000 }
3001
TEST_F(ValidationErrorTest,FieldTypeDefinedInUndeclaredDependency)3002 TEST_F(ValidationErrorTest, FieldTypeDefinedInUndeclaredDependency) {
3003 BuildFile(
3004 "name: \"bar.proto\" "
3005 "message_type { name: \"Bar\" } ");
3006
3007 BuildFileWithErrors(
3008 "name: \"foo.proto\" "
3009 "message_type {"
3010 " name: \"Foo\""
3011 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
3012 "}",
3013 "foo.proto: Foo.foo: TYPE: \"Bar\" seems to be defined in \"bar.proto\", "
3014 "which is not imported by \"foo.proto\". To use it here, please add the "
3015 "necessary import.\n");
3016 }
3017
TEST_F(ValidationErrorTest,FieldTypeDefinedInIndirectDependency)3018 TEST_F(ValidationErrorTest, FieldTypeDefinedInIndirectDependency) {
3019 // Test for hidden dependencies.
3020 //
3021 // // bar.proto
3022 // message Bar{}
3023 //
3024 // // forward.proto
3025 // import "bar.proto"
3026 //
3027 // // foo.proto
3028 // import "forward.proto"
3029 // message Foo {
3030 // optional Bar foo = 1; // Error, needs to import bar.proto explicitly.
3031 // }
3032 //
3033 BuildFile(
3034 "name: \"bar.proto\" "
3035 "message_type { name: \"Bar\" }");
3036
3037 BuildFile(
3038 "name: \"forward.proto\""
3039 "dependency: \"bar.proto\"");
3040
3041 BuildFileWithErrors(
3042 "name: \"foo.proto\" "
3043 "dependency: \"forward.proto\" "
3044 "message_type {"
3045 " name: \"Foo\""
3046 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
3047 "}",
3048 "foo.proto: Foo.foo: TYPE: \"Bar\" seems to be defined in \"bar.proto\", "
3049 "which is not imported by \"foo.proto\". To use it here, please add the "
3050 "necessary import.\n");
3051 }
3052
TEST_F(ValidationErrorTest,FieldTypeDefinedInPublicDependency)3053 TEST_F(ValidationErrorTest, FieldTypeDefinedInPublicDependency) {
3054 // Test for public dependencies.
3055 //
3056 // // bar.proto
3057 // message Bar{}
3058 //
3059 // // forward.proto
3060 // import public "bar.proto"
3061 //
3062 // // foo.proto
3063 // import "forward.proto"
3064 // message Foo {
3065 // optional Bar foo = 1; // Correct. "bar.proto" is public imported into
3066 // // forward.proto, so when "foo.proto" imports
3067 // // "forward.proto", it imports "bar.proto" too.
3068 // }
3069 //
3070 BuildFile(
3071 "name: \"bar.proto\" "
3072 "message_type { name: \"Bar\" }");
3073
3074 BuildFile(
3075 "name: \"forward.proto\""
3076 "dependency: \"bar.proto\" "
3077 "public_dependency: 0");
3078
3079 BuildFile(
3080 "name: \"foo.proto\" "
3081 "dependency: \"forward.proto\" "
3082 "message_type {"
3083 " name: \"Foo\""
3084 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
3085 "}");
3086 }
3087
TEST_F(ValidationErrorTest,FieldTypeDefinedInTransitivePublicDependency)3088 TEST_F(ValidationErrorTest, FieldTypeDefinedInTransitivePublicDependency) {
3089 // Test for public dependencies.
3090 //
3091 // // bar.proto
3092 // message Bar{}
3093 //
3094 // // forward.proto
3095 // import public "bar.proto"
3096 //
3097 // // forward2.proto
3098 // import public "forward.proto"
3099 //
3100 // // foo.proto
3101 // import "forward2.proto"
3102 // message Foo {
3103 // optional Bar foo = 1; // Correct, public imports are transitive.
3104 // }
3105 //
3106 BuildFile(
3107 "name: \"bar.proto\" "
3108 "message_type { name: \"Bar\" }");
3109
3110 BuildFile(
3111 "name: \"forward.proto\""
3112 "dependency: \"bar.proto\" "
3113 "public_dependency: 0");
3114
3115 BuildFile(
3116 "name: \"forward2.proto\""
3117 "dependency: \"forward.proto\" "
3118 "public_dependency: 0");
3119
3120 BuildFile(
3121 "name: \"foo.proto\" "
3122 "dependency: \"forward2.proto\" "
3123 "message_type {"
3124 " name: \"Foo\""
3125 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
3126 "}");
3127 }
3128
TEST_F(ValidationErrorTest,FieldTypeDefinedInPrivateDependencyOfPublicDependency)3129 TEST_F(ValidationErrorTest,
3130 FieldTypeDefinedInPrivateDependencyOfPublicDependency) {
3131 // Test for public dependencies.
3132 //
3133 // // bar.proto
3134 // message Bar{}
3135 //
3136 // // forward.proto
3137 // import "bar.proto"
3138 //
3139 // // forward2.proto
3140 // import public "forward.proto"
3141 //
3142 // // foo.proto
3143 // import "forward2.proto"
3144 // message Foo {
3145 // optional Bar foo = 1; // Error, the "bar.proto" is not public imported
3146 // // into "forward.proto", so will not be imported
3147 // // into either "forward2.proto" or "foo.proto".
3148 // }
3149 //
3150 BuildFile(
3151 "name: \"bar.proto\" "
3152 "message_type { name: \"Bar\" }");
3153
3154 BuildFile(
3155 "name: \"forward.proto\""
3156 "dependency: \"bar.proto\"");
3157
3158 BuildFile(
3159 "name: \"forward2.proto\""
3160 "dependency: \"forward.proto\" "
3161 "public_dependency: 0");
3162
3163 BuildFileWithErrors(
3164 "name: \"foo.proto\" "
3165 "dependency: \"forward2.proto\" "
3166 "message_type {"
3167 " name: \"Foo\""
3168 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
3169 "}",
3170 "foo.proto: Foo.foo: TYPE: \"Bar\" seems to be defined in \"bar.proto\", "
3171 "which is not imported by \"foo.proto\". To use it here, please add the "
3172 "necessary import.\n");
3173 }
3174
3175
TEST_F(ValidationErrorTest,SearchMostLocalFirst)3176 TEST_F(ValidationErrorTest, SearchMostLocalFirst) {
3177 // The following should produce an error that Bar.Baz is not defined:
3178 // message Bar { message Baz {} }
3179 // message Foo {
3180 // message Bar {
3181 // // Placing "message Baz{}" here, or removing Foo.Bar altogether,
3182 // // would fix the error.
3183 // }
3184 // optional Bar.Baz baz = 1;
3185 // }
3186 // An one point the lookup code incorrectly did not produce an error in this
3187 // case, because when looking for Bar.Baz, it would try "Foo.Bar.Baz" first,
3188 // fail, and ten try "Bar.Baz" and succeed, even though "Bar" should actually
3189 // refer to the inner Bar, not the outer one.
3190 BuildFileWithErrors(
3191 "name: \"foo.proto\" "
3192 "message_type {"
3193 " name: \"Bar\""
3194 " nested_type { name: \"Baz\" }"
3195 "}"
3196 "message_type {"
3197 " name: \"Foo\""
3198 " nested_type { name: \"Bar\" }"
3199 " field { name:\"baz\" number:1 label:LABEL_OPTIONAL"
3200 " type_name:\"Bar.Baz\" }"
3201 "}",
3202
3203 "foo.proto: Foo.baz: TYPE: \"Bar.Baz\" is not defined.\n");
3204 }
3205
TEST_F(ValidationErrorTest,SearchMostLocalFirst2)3206 TEST_F(ValidationErrorTest, SearchMostLocalFirst2) {
3207 // This test would find the most local "Bar" first, and does, but
3208 // proceeds to find the outer one because the inner one's not an
3209 // aggregate.
3210 BuildFile(
3211 "name: \"foo.proto\" "
3212 "message_type {"
3213 " name: \"Bar\""
3214 " nested_type { name: \"Baz\" }"
3215 "}"
3216 "message_type {"
3217 " name: \"Foo\""
3218 " field { name: \"Bar\" number:1 type:TYPE_BYTES } "
3219 " field { name:\"baz\" number:2 label:LABEL_OPTIONAL"
3220 " type_name:\"Bar.Baz\" }"
3221 "}");
3222 }
3223
TEST_F(ValidationErrorTest,PackageOriginallyDeclaredInTransitiveDependent)3224 TEST_F(ValidationErrorTest, PackageOriginallyDeclaredInTransitiveDependent) {
3225 // Imagine we have the following:
3226 //
3227 // foo.proto:
3228 // package foo.bar;
3229 // bar.proto:
3230 // package foo.bar;
3231 // import "foo.proto";
3232 // message Bar {}
3233 // baz.proto:
3234 // package foo;
3235 // import "bar.proto"
3236 // message Baz { optional bar.Bar qux = 1; }
3237 //
3238 // When validating baz.proto, we will look up "bar.Bar". As part of this
3239 // lookup, we first lookup "bar" then try to find "Bar" within it. "bar"
3240 // should resolve to "foo.bar". Note, though, that "foo.bar" was originally
3241 // defined in foo.proto, which is not a direct dependency of baz.proto. The
3242 // implementation of FindSymbol() normally only returns symbols in direct
3243 // dependencies, not indirect ones. This test insures that this does not
3244 // prevent it from finding "foo.bar".
3245
3246 BuildFile(
3247 "name: \"foo.proto\" "
3248 "package: \"foo.bar\" ");
3249 BuildFile(
3250 "name: \"bar.proto\" "
3251 "package: \"foo.bar\" "
3252 "dependency: \"foo.proto\" "
3253 "message_type { name: \"Bar\" }");
3254 BuildFile(
3255 "name: \"baz.proto\" "
3256 "package: \"foo\" "
3257 "dependency: \"bar.proto\" "
3258 "message_type { "
3259 " name: \"Baz\" "
3260 " field { name:\"qux\" number:1 label:LABEL_OPTIONAL "
3261 " type_name:\"bar.Bar\" }"
3262 "}");
3263 }
3264
TEST_F(ValidationErrorTest,FieldTypeNotAType)3265 TEST_F(ValidationErrorTest, FieldTypeNotAType) {
3266 BuildFileWithErrors(
3267 "name: \"foo.proto\" "
3268 "message_type {"
3269 " name: \"Foo\""
3270 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL "
3271 " type_name:\".Foo.bar\" }"
3272 " field { name:\"bar\" number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }"
3273 "}",
3274
3275 "foo.proto: Foo.foo: TYPE: \".Foo.bar\" is not a type.\n");
3276 }
3277
TEST_F(ValidationErrorTest,RelativeFieldTypeNotAType)3278 TEST_F(ValidationErrorTest, RelativeFieldTypeNotAType) {
3279 BuildFileWithErrors(
3280 "name: \"foo.proto\" "
3281 "message_type {"
3282 " nested_type {"
3283 " name: \"Bar\""
3284 " field { name:\"Baz\" number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }"
3285 " }"
3286 " name: \"Foo\""
3287 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL "
3288 " type_name:\"Bar.Baz\" }"
3289 "}",
3290 "foo.proto: Foo.foo: TYPE: \"Bar.Baz\" is not a type.\n");
3291 }
3292
TEST_F(ValidationErrorTest,FieldTypeMayBeItsName)3293 TEST_F(ValidationErrorTest, FieldTypeMayBeItsName) {
3294 BuildFile(
3295 "name: \"foo.proto\" "
3296 "message_type {"
3297 " name: \"Bar\""
3298 "}"
3299 "message_type {"
3300 " name: \"Foo\""
3301 " field { name:\"Bar\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
3302 "}");
3303 }
3304
TEST_F(ValidationErrorTest,EnumFieldTypeIsMessage)3305 TEST_F(ValidationErrorTest, EnumFieldTypeIsMessage) {
3306 BuildFileWithErrors(
3307 "name: \"foo.proto\" "
3308 "message_type { name: \"Bar\" } "
3309 "message_type {"
3310 " name: \"Foo\""
3311 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_ENUM"
3312 " type_name:\"Bar\" }"
3313 "}",
3314
3315 "foo.proto: Foo.foo: TYPE: \"Bar\" is not an enum type.\n");
3316 }
3317
TEST_F(ValidationErrorTest,MessageFieldTypeIsEnum)3318 TEST_F(ValidationErrorTest, MessageFieldTypeIsEnum) {
3319 BuildFileWithErrors(
3320 "name: \"foo.proto\" "
3321 "enum_type { name: \"Bar\" value { name:\"DUMMY\" number:0 } } "
3322 "message_type {"
3323 " name: \"Foo\""
3324 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_MESSAGE"
3325 " type_name:\"Bar\" }"
3326 "}",
3327
3328 "foo.proto: Foo.foo: TYPE: \"Bar\" is not a message type.\n");
3329 }
3330
TEST_F(ValidationErrorTest,BadEnumDefaultValue)3331 TEST_F(ValidationErrorTest, BadEnumDefaultValue) {
3332 BuildFileWithErrors(
3333 "name: \"foo.proto\" "
3334 "enum_type { name: \"Bar\" value { name:\"DUMMY\" number:0 } } "
3335 "message_type {"
3336 " name: \"Foo\""
3337 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\""
3338 " default_value:\"NO_SUCH_VALUE\" }"
3339 "}",
3340
3341 "foo.proto: Foo.foo: DEFAULT_VALUE: Enum type \"Bar\" has no value named "
3342 "\"NO_SUCH_VALUE\".\n");
3343 }
3344
TEST_F(ValidationErrorTest,PrimitiveWithTypeName)3345 TEST_F(ValidationErrorTest, PrimitiveWithTypeName) {
3346 BuildFileWithErrors(
3347 "name: \"foo.proto\" "
3348 "message_type {"
3349 " name: \"Foo\""
3350 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_INT32"
3351 " type_name:\"Foo\" }"
3352 "}",
3353
3354 "foo.proto: Foo.foo: TYPE: Field with primitive type has type_name.\n");
3355 }
3356
TEST_F(ValidationErrorTest,NonPrimitiveWithoutTypeName)3357 TEST_F(ValidationErrorTest, NonPrimitiveWithoutTypeName) {
3358 BuildFileWithErrors(
3359 "name: \"foo.proto\" "
3360 "message_type {"
3361 " name: \"Foo\""
3362 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_MESSAGE }"
3363 "}",
3364
3365 "foo.proto: Foo.foo: TYPE: Field with message or enum type missing "
3366 "type_name.\n");
3367 }
3368
TEST_F(ValidationErrorTest,InputTypeNotDefined)3369 TEST_F(ValidationErrorTest, InputTypeNotDefined) {
3370 BuildFileWithErrors(
3371 "name: \"foo.proto\" "
3372 "message_type { name: \"Foo\" } "
3373 "service {"
3374 " name: \"TestService\""
3375 " method { name: \"A\" input_type: \"Bar\" output_type: \"Foo\" }"
3376 "}",
3377
3378 "foo.proto: TestService.A: INPUT_TYPE: \"Bar\" is not defined.\n"
3379 );
3380 }
3381
TEST_F(ValidationErrorTest,InputTypeNotAMessage)3382 TEST_F(ValidationErrorTest, InputTypeNotAMessage) {
3383 BuildFileWithErrors(
3384 "name: \"foo.proto\" "
3385 "message_type { name: \"Foo\" } "
3386 "enum_type { name: \"Bar\" value { name:\"DUMMY\" number:0 } } "
3387 "service {"
3388 " name: \"TestService\""
3389 " method { name: \"A\" input_type: \"Bar\" output_type: \"Foo\" }"
3390 "}",
3391
3392 "foo.proto: TestService.A: INPUT_TYPE: \"Bar\" is not a message type.\n"
3393 );
3394 }
3395
TEST_F(ValidationErrorTest,OutputTypeNotDefined)3396 TEST_F(ValidationErrorTest, OutputTypeNotDefined) {
3397 BuildFileWithErrors(
3398 "name: \"foo.proto\" "
3399 "message_type { name: \"Foo\" } "
3400 "service {"
3401 " name: \"TestService\""
3402 " method { name: \"A\" input_type: \"Foo\" output_type: \"Bar\" }"
3403 "}",
3404
3405 "foo.proto: TestService.A: OUTPUT_TYPE: \"Bar\" is not defined.\n"
3406 );
3407 }
3408
TEST_F(ValidationErrorTest,OutputTypeNotAMessage)3409 TEST_F(ValidationErrorTest, OutputTypeNotAMessage) {
3410 BuildFileWithErrors(
3411 "name: \"foo.proto\" "
3412 "message_type { name: \"Foo\" } "
3413 "enum_type { name: \"Bar\" value { name:\"DUMMY\" number:0 } } "
3414 "service {"
3415 " name: \"TestService\""
3416 " method { name: \"A\" input_type: \"Foo\" output_type: \"Bar\" }"
3417 "}",
3418
3419 "foo.proto: TestService.A: OUTPUT_TYPE: \"Bar\" is not a message type.\n"
3420 );
3421 }
3422
3423
TEST_F(ValidationErrorTest,IllegalPackedField)3424 TEST_F(ValidationErrorTest, IllegalPackedField) {
3425 BuildFileWithErrors(
3426 "name: \"foo.proto\" "
3427 "message_type {\n"
3428 " name: \"Foo\""
3429 " field { name:\"packed_string\" number:1 label:LABEL_REPEATED "
3430 " type:TYPE_STRING "
3431 " options { uninterpreted_option {"
3432 " name { name_part: \"packed\" is_extension: false }"
3433 " identifier_value: \"true\" }}}\n"
3434 " field { name:\"packed_message\" number:3 label:LABEL_REPEATED "
3435 " type_name: \"Foo\""
3436 " options { uninterpreted_option {"
3437 " name { name_part: \"packed\" is_extension: false }"
3438 " identifier_value: \"true\" }}}\n"
3439 " field { name:\"optional_int32\" number: 4 label: LABEL_OPTIONAL "
3440 " type:TYPE_INT32 "
3441 " options { uninterpreted_option {"
3442 " name { name_part: \"packed\" is_extension: false }"
3443 " identifier_value: \"true\" }}}\n"
3444 "}",
3445
3446 "foo.proto: Foo.packed_string: TYPE: [packed = true] can only be "
3447 "specified for repeated primitive fields.\n"
3448 "foo.proto: Foo.packed_message: TYPE: [packed = true] can only be "
3449 "specified for repeated primitive fields.\n"
3450 "foo.proto: Foo.optional_int32: TYPE: [packed = true] can only be "
3451 "specified for repeated primitive fields.\n"
3452 );
3453 }
3454
TEST_F(ValidationErrorTest,OptionWrongType)3455 TEST_F(ValidationErrorTest, OptionWrongType) {
3456 BuildFileWithErrors(
3457 "name: \"foo.proto\" "
3458 "message_type { "
3459 " name: \"TestMessage\" "
3460 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_STRING "
3461 " options { uninterpreted_option { name { name_part: \"ctype\" "
3462 " is_extension: false }"
3463 " positive_int_value: 1 }"
3464 " }"
3465 " }"
3466 "}\n",
3467
3468 "foo.proto: TestMessage.foo: OPTION_VALUE: Value must be identifier for "
3469 "enum-valued option \"google.protobuf.FieldOptions.ctype\".\n");
3470 }
3471
TEST_F(ValidationErrorTest,OptionExtendsAtomicType)3472 TEST_F(ValidationErrorTest, OptionExtendsAtomicType) {
3473 BuildFileWithErrors(
3474 "name: \"foo.proto\" "
3475 "message_type { "
3476 " name: \"TestMessage\" "
3477 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_STRING "
3478 " options { uninterpreted_option { name { name_part: \"ctype\" "
3479 " is_extension: false }"
3480 " name { name_part: \"foo\" "
3481 " is_extension: true }"
3482 " positive_int_value: 1 }"
3483 " }"
3484 " }"
3485 "}\n",
3486
3487 "foo.proto: TestMessage.foo: OPTION_NAME: Option \"ctype\" is an "
3488 "atomic type, not a message.\n");
3489 }
3490
TEST_F(ValidationErrorTest,DupOption)3491 TEST_F(ValidationErrorTest, DupOption) {
3492 BuildFileWithErrors(
3493 "name: \"foo.proto\" "
3494 "message_type { "
3495 " name: \"TestMessage\" "
3496 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_UINT32 "
3497 " options { uninterpreted_option { name { name_part: \"ctype\" "
3498 " is_extension: false }"
3499 " identifier_value: \"CORD\" }"
3500 " uninterpreted_option { name { name_part: \"ctype\" "
3501 " is_extension: false }"
3502 " identifier_value: \"CORD\" }"
3503 " }"
3504 " }"
3505 "}\n",
3506
3507 "foo.proto: TestMessage.foo: OPTION_NAME: Option \"ctype\" was "
3508 "already set.\n");
3509 }
3510
TEST_F(ValidationErrorTest,InvalidOptionName)3511 TEST_F(ValidationErrorTest, InvalidOptionName) {
3512 BuildFileWithErrors(
3513 "name: \"foo.proto\" "
3514 "message_type { "
3515 " name: \"TestMessage\" "
3516 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_BOOL "
3517 " options { uninterpreted_option { "
3518 " name { name_part: \"uninterpreted_option\" "
3519 " is_extension: false }"
3520 " positive_int_value: 1 "
3521 " }"
3522 " }"
3523 " }"
3524 "}\n",
3525
3526 "foo.proto: TestMessage.foo: OPTION_NAME: Option must not use "
3527 "reserved name \"uninterpreted_option\".\n");
3528 }
3529
TEST_F(ValidationErrorTest,RepeatedOption)3530 TEST_F(ValidationErrorTest, RepeatedOption) {
3531 BuildDescriptorMessagesInTestPool();
3532
3533 BuildFileWithErrors(
3534 "name: \"foo.proto\" "
3535 "dependency: \"google/protobuf/descriptor.proto\" "
3536 "extension { name: \"foo\" number: 7672757 label: LABEL_REPEATED "
3537 " type: TYPE_FLOAT extendee: \"google.protobuf.FileOptions\" }"
3538 "options { uninterpreted_option { name { name_part: \"foo\" "
3539 " is_extension: true } "
3540 " double_value: 1.2 } }",
3541
3542 "foo.proto: foo.proto: OPTION_NAME: Option field \"(foo)\" is repeated. "
3543 "Repeated options are not supported.\n");
3544 }
3545
TEST_F(ValidationErrorTest,CustomOptionConflictingFieldNumber)3546 TEST_F(ValidationErrorTest, CustomOptionConflictingFieldNumber) {
3547 BuildDescriptorMessagesInTestPool();
3548
3549 BuildFileWithErrors(
3550 "name: \"foo.proto\" "
3551 "dependency: \"google/protobuf/descriptor.proto\" "
3552 "extension { name: \"foo1\" number: 7672757 label: LABEL_OPTIONAL "
3553 " type: TYPE_INT32 extendee: \"google.protobuf.FieldOptions\" }"
3554 "extension { name: \"foo2\" number: 7672757 label: LABEL_OPTIONAL "
3555 " type: TYPE_INT32 extendee: \"google.protobuf.FieldOptions\" }",
3556
3557 "foo.proto: foo2: NUMBER: Extension number 7672757 has already been used "
3558 "in \"google.protobuf.FieldOptions\" by extension \"foo1\".\n");
3559 }
3560
TEST_F(ValidationErrorTest,Int32OptionValueOutOfPositiveRange)3561 TEST_F(ValidationErrorTest, Int32OptionValueOutOfPositiveRange) {
3562 BuildDescriptorMessagesInTestPool();
3563
3564 BuildFileWithErrors(
3565 "name: \"foo.proto\" "
3566 "dependency: \"google/protobuf/descriptor.proto\" "
3567 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
3568 " type: TYPE_INT32 extendee: \"google.protobuf.FileOptions\" }"
3569 "options { uninterpreted_option { name { name_part: \"foo\" "
3570 " is_extension: true } "
3571 " positive_int_value: 0x80000000 } "
3572 "}",
3573
3574 "foo.proto: foo.proto: OPTION_VALUE: Value out of range "
3575 "for int32 option \"foo\".\n");
3576 }
3577
TEST_F(ValidationErrorTest,Int32OptionValueOutOfNegativeRange)3578 TEST_F(ValidationErrorTest, Int32OptionValueOutOfNegativeRange) {
3579 BuildDescriptorMessagesInTestPool();
3580
3581 BuildFileWithErrors(
3582 "name: \"foo.proto\" "
3583 "dependency: \"google/protobuf/descriptor.proto\" "
3584 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
3585 " type: TYPE_INT32 extendee: \"google.protobuf.FileOptions\" }"
3586 "options { uninterpreted_option { name { name_part: \"foo\" "
3587 " is_extension: true } "
3588 " negative_int_value: -0x80000001 } "
3589 "}",
3590
3591 "foo.proto: foo.proto: OPTION_VALUE: Value out of range "
3592 "for int32 option \"foo\".\n");
3593 }
3594
TEST_F(ValidationErrorTest,Int32OptionValueIsNotPositiveInt)3595 TEST_F(ValidationErrorTest, Int32OptionValueIsNotPositiveInt) {
3596 BuildDescriptorMessagesInTestPool();
3597
3598 BuildFileWithErrors(
3599 "name: \"foo.proto\" "
3600 "dependency: \"google/protobuf/descriptor.proto\" "
3601 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
3602 " type: TYPE_INT32 extendee: \"google.protobuf.FileOptions\" }"
3603 "options { uninterpreted_option { name { name_part: \"foo\" "
3604 " is_extension: true } "
3605 " string_value: \"5\" } }",
3606
3607 "foo.proto: foo.proto: OPTION_VALUE: Value must be integer "
3608 "for int32 option \"foo\".\n");
3609 }
3610
TEST_F(ValidationErrorTest,Int64OptionValueOutOfRange)3611 TEST_F(ValidationErrorTest, Int64OptionValueOutOfRange) {
3612 BuildDescriptorMessagesInTestPool();
3613
3614 BuildFileWithErrors(
3615 "name: \"foo.proto\" "
3616 "dependency: \"google/protobuf/descriptor.proto\" "
3617 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
3618 " type: TYPE_INT64 extendee: \"google.protobuf.FileOptions\" }"
3619 "options { uninterpreted_option { name { name_part: \"foo\" "
3620 " is_extension: true } "
3621 " positive_int_value: 0x8000000000000000 } "
3622 "}",
3623
3624 "foo.proto: foo.proto: OPTION_VALUE: Value out of range "
3625 "for int64 option \"foo\".\n");
3626 }
3627
TEST_F(ValidationErrorTest,Int64OptionValueIsNotPositiveInt)3628 TEST_F(ValidationErrorTest, Int64OptionValueIsNotPositiveInt) {
3629 BuildDescriptorMessagesInTestPool();
3630
3631 BuildFileWithErrors(
3632 "name: \"foo.proto\" "
3633 "dependency: \"google/protobuf/descriptor.proto\" "
3634 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
3635 " type: TYPE_INT64 extendee: \"google.protobuf.FileOptions\" }"
3636 "options { uninterpreted_option { name { name_part: \"foo\" "
3637 " is_extension: true } "
3638 " identifier_value: \"5\" } }",
3639
3640 "foo.proto: foo.proto: OPTION_VALUE: Value must be integer "
3641 "for int64 option \"foo\".\n");
3642 }
3643
TEST_F(ValidationErrorTest,UInt32OptionValueOutOfRange)3644 TEST_F(ValidationErrorTest, UInt32OptionValueOutOfRange) {
3645 BuildDescriptorMessagesInTestPool();
3646
3647 BuildFileWithErrors(
3648 "name: \"foo.proto\" "
3649 "dependency: \"google/protobuf/descriptor.proto\" "
3650 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
3651 " type: TYPE_UINT32 extendee: \"google.protobuf.FileOptions\" }"
3652 "options { uninterpreted_option { name { name_part: \"foo\" "
3653 " is_extension: true } "
3654 " positive_int_value: 0x100000000 } }",
3655
3656 "foo.proto: foo.proto: OPTION_VALUE: Value out of range "
3657 "for uint32 option \"foo\".\n");
3658 }
3659
TEST_F(ValidationErrorTest,UInt32OptionValueIsNotPositiveInt)3660 TEST_F(ValidationErrorTest, UInt32OptionValueIsNotPositiveInt) {
3661 BuildDescriptorMessagesInTestPool();
3662
3663 BuildFileWithErrors(
3664 "name: \"foo.proto\" "
3665 "dependency: \"google/protobuf/descriptor.proto\" "
3666 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
3667 " type: TYPE_UINT32 extendee: \"google.protobuf.FileOptions\" }"
3668 "options { uninterpreted_option { name { name_part: \"foo\" "
3669 " is_extension: true } "
3670 " double_value: -5.6 } }",
3671
3672 "foo.proto: foo.proto: OPTION_VALUE: Value must be non-negative integer "
3673 "for uint32 option \"foo\".\n");
3674 }
3675
TEST_F(ValidationErrorTest,UInt64OptionValueIsNotPositiveInt)3676 TEST_F(ValidationErrorTest, UInt64OptionValueIsNotPositiveInt) {
3677 BuildDescriptorMessagesInTestPool();
3678
3679 BuildFileWithErrors(
3680 "name: \"foo.proto\" "
3681 "dependency: \"google/protobuf/descriptor.proto\" "
3682 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
3683 " type: TYPE_UINT64 extendee: \"google.protobuf.FileOptions\" }"
3684 "options { uninterpreted_option { name { name_part: \"foo\" "
3685 " is_extension: true } "
3686 " negative_int_value: -5 } }",
3687
3688 "foo.proto: foo.proto: OPTION_VALUE: Value must be non-negative integer "
3689 "for uint64 option \"foo\".\n");
3690 }
3691
TEST_F(ValidationErrorTest,FloatOptionValueIsNotNumber)3692 TEST_F(ValidationErrorTest, FloatOptionValueIsNotNumber) {
3693 BuildDescriptorMessagesInTestPool();
3694
3695 BuildFileWithErrors(
3696 "name: \"foo.proto\" "
3697 "dependency: \"google/protobuf/descriptor.proto\" "
3698 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
3699 " type: TYPE_FLOAT extendee: \"google.protobuf.FileOptions\" }"
3700 "options { uninterpreted_option { name { name_part: \"foo\" "
3701 " is_extension: true } "
3702 " string_value: \"bar\" } }",
3703
3704 "foo.proto: foo.proto: OPTION_VALUE: Value must be number "
3705 "for float option \"foo\".\n");
3706 }
3707
TEST_F(ValidationErrorTest,DoubleOptionValueIsNotNumber)3708 TEST_F(ValidationErrorTest, DoubleOptionValueIsNotNumber) {
3709 BuildDescriptorMessagesInTestPool();
3710
3711 BuildFileWithErrors(
3712 "name: \"foo.proto\" "
3713 "dependency: \"google/protobuf/descriptor.proto\" "
3714 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
3715 " type: TYPE_DOUBLE extendee: \"google.protobuf.FileOptions\" }"
3716 "options { uninterpreted_option { name { name_part: \"foo\" "
3717 " is_extension: true } "
3718 " string_value: \"bar\" } }",
3719
3720 "foo.proto: foo.proto: OPTION_VALUE: Value must be number "
3721 "for double option \"foo\".\n");
3722 }
3723
TEST_F(ValidationErrorTest,BoolOptionValueIsNotTrueOrFalse)3724 TEST_F(ValidationErrorTest, BoolOptionValueIsNotTrueOrFalse) {
3725 BuildDescriptorMessagesInTestPool();
3726
3727 BuildFileWithErrors(
3728 "name: \"foo.proto\" "
3729 "dependency: \"google/protobuf/descriptor.proto\" "
3730 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
3731 " type: TYPE_BOOL extendee: \"google.protobuf.FileOptions\" }"
3732 "options { uninterpreted_option { name { name_part: \"foo\" "
3733 " is_extension: true } "
3734 " identifier_value: \"bar\" } }",
3735
3736 "foo.proto: foo.proto: OPTION_VALUE: Value must be \"true\" or \"false\" "
3737 "for boolean option \"foo\".\n");
3738 }
3739
TEST_F(ValidationErrorTest,EnumOptionValueIsNotIdentifier)3740 TEST_F(ValidationErrorTest, EnumOptionValueIsNotIdentifier) {
3741 BuildDescriptorMessagesInTestPool();
3742
3743 BuildFileWithErrors(
3744 "name: \"foo.proto\" "
3745 "dependency: \"google/protobuf/descriptor.proto\" "
3746 "enum_type { name: \"FooEnum\" value { name: \"BAR\" number: 1 } "
3747 " value { name: \"BAZ\" number: 2 } }"
3748 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
3749 " type: TYPE_ENUM type_name: \"FooEnum\" "
3750 " extendee: \"google.protobuf.FileOptions\" }"
3751 "options { uninterpreted_option { name { name_part: \"foo\" "
3752 " is_extension: true } "
3753 " string_value: \"QUUX\" } }",
3754
3755 "foo.proto: foo.proto: OPTION_VALUE: Value must be identifier for "
3756 "enum-valued option \"foo\".\n");
3757 }
3758
TEST_F(ValidationErrorTest,EnumOptionValueIsNotEnumValueName)3759 TEST_F(ValidationErrorTest, EnumOptionValueIsNotEnumValueName) {
3760 BuildDescriptorMessagesInTestPool();
3761
3762 BuildFileWithErrors(
3763 "name: \"foo.proto\" "
3764 "dependency: \"google/protobuf/descriptor.proto\" "
3765 "enum_type { name: \"FooEnum\" value { name: \"BAR\" number: 1 } "
3766 " value { name: \"BAZ\" number: 2 } }"
3767 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
3768 " type: TYPE_ENUM type_name: \"FooEnum\" "
3769 " extendee: \"google.protobuf.FileOptions\" }"
3770 "options { uninterpreted_option { name { name_part: \"foo\" "
3771 " is_extension: true } "
3772 " identifier_value: \"QUUX\" } }",
3773
3774 "foo.proto: foo.proto: OPTION_VALUE: Enum type \"FooEnum\" has no value "
3775 "named \"QUUX\" for option \"foo\".\n");
3776 }
3777
TEST_F(ValidationErrorTest,EnumOptionValueIsSiblingEnumValueName)3778 TEST_F(ValidationErrorTest, EnumOptionValueIsSiblingEnumValueName) {
3779 BuildDescriptorMessagesInTestPool();
3780
3781 BuildFileWithErrors(
3782 "name: \"foo.proto\" "
3783 "dependency: \"google/protobuf/descriptor.proto\" "
3784 "enum_type { name: \"FooEnum1\" value { name: \"BAR\" number: 1 } "
3785 " value { name: \"BAZ\" number: 2 } }"
3786 "enum_type { name: \"FooEnum2\" value { name: \"QUX\" number: 1 } "
3787 " value { name: \"QUUX\" number: 2 } }"
3788 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
3789 " type: TYPE_ENUM type_name: \"FooEnum1\" "
3790 " extendee: \"google.protobuf.FileOptions\" }"
3791 "options { uninterpreted_option { name { name_part: \"foo\" "
3792 " is_extension: true } "
3793 " identifier_value: \"QUUX\" } }",
3794
3795 "foo.proto: foo.proto: OPTION_VALUE: Enum type \"FooEnum1\" has no value "
3796 "named \"QUUX\" for option \"foo\". This appears to be a value from a "
3797 "sibling type.\n");
3798 }
3799
TEST_F(ValidationErrorTest,StringOptionValueIsNotString)3800 TEST_F(ValidationErrorTest, StringOptionValueIsNotString) {
3801 BuildDescriptorMessagesInTestPool();
3802
3803 BuildFileWithErrors(
3804 "name: \"foo.proto\" "
3805 "dependency: \"google/protobuf/descriptor.proto\" "
3806 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
3807 " type: TYPE_STRING extendee: \"google.protobuf.FileOptions\" }"
3808 "options { uninterpreted_option { name { name_part: \"foo\" "
3809 " is_extension: true } "
3810 " identifier_value: \"QUUX\" } }",
3811
3812 "foo.proto: foo.proto: OPTION_VALUE: Value must be quoted string for "
3813 "string option \"foo\".\n");
3814 }
3815
3816 // Helper function for tests that check for aggregate value parsing
3817 // errors. The "value" argument is embedded inside the
3818 // "uninterpreted_option" portion of the result.
EmbedAggregateValue(const char * value)3819 static string EmbedAggregateValue(const char* value) {
3820 return strings::Substitute(
3821 "name: \"foo.proto\" "
3822 "dependency: \"google/protobuf/descriptor.proto\" "
3823 "message_type { name: \"Foo\" } "
3824 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
3825 " type: TYPE_MESSAGE type_name: \"Foo\" "
3826 " extendee: \"google.protobuf.FileOptions\" }"
3827 "options { uninterpreted_option { name { name_part: \"foo\" "
3828 " is_extension: true } "
3829 " $0 } }",
3830 value);
3831 }
3832
TEST_F(ValidationErrorTest,AggregateValueNotFound)3833 TEST_F(ValidationErrorTest, AggregateValueNotFound) {
3834 BuildDescriptorMessagesInTestPool();
3835
3836 BuildFileWithErrors(
3837 EmbedAggregateValue("string_value: \"\""),
3838 "foo.proto: foo.proto: OPTION_VALUE: Option \"foo\" is a message. "
3839 "To set the entire message, use syntax like "
3840 "\"foo = { <proto text format> }\". To set fields within it, use "
3841 "syntax like \"foo.foo = value\".\n");
3842 }
3843
TEST_F(ValidationErrorTest,AggregateValueParseError)3844 TEST_F(ValidationErrorTest, AggregateValueParseError) {
3845 BuildDescriptorMessagesInTestPool();
3846
3847 BuildFileWithErrors(
3848 EmbedAggregateValue("aggregate_value: \"1+2\""),
3849 "foo.proto: foo.proto: OPTION_VALUE: Error while parsing option "
3850 "value for \"foo\": Expected identifier.\n");
3851 }
3852
TEST_F(ValidationErrorTest,AggregateValueUnknownFields)3853 TEST_F(ValidationErrorTest, AggregateValueUnknownFields) {
3854 BuildDescriptorMessagesInTestPool();
3855
3856 BuildFileWithErrors(
3857 EmbedAggregateValue("aggregate_value: \"x:100\""),
3858 "foo.proto: foo.proto: OPTION_VALUE: Error while parsing option "
3859 "value for \"foo\": Message type \"Foo\" has no field named \"x\".\n");
3860 }
3861
TEST_F(ValidationErrorTest,NotLiteImportsLite)3862 TEST_F(ValidationErrorTest, NotLiteImportsLite) {
3863 BuildFile(
3864 "name: \"bar.proto\" "
3865 "options { optimize_for: LITE_RUNTIME } ");
3866
3867 BuildFileWithErrors(
3868 "name: \"foo.proto\" "
3869 "dependency: \"bar.proto\" ",
3870
3871 "foo.proto: foo.proto: OTHER: Files that do not use optimize_for = "
3872 "LITE_RUNTIME cannot import files which do use this option. This file "
3873 "is not lite, but it imports \"bar.proto\" which is.\n");
3874 }
3875
TEST_F(ValidationErrorTest,LiteExtendsNotLite)3876 TEST_F(ValidationErrorTest, LiteExtendsNotLite) {
3877 BuildFile(
3878 "name: \"bar.proto\" "
3879 "message_type: {"
3880 " name: \"Bar\""
3881 " extension_range { start: 1 end: 1000 }"
3882 "}");
3883
3884 BuildFileWithErrors(
3885 "name: \"foo.proto\" "
3886 "dependency: \"bar.proto\" "
3887 "options { optimize_for: LITE_RUNTIME } "
3888 "extension { name: \"ext\" number: 123 label: LABEL_OPTIONAL "
3889 " type: TYPE_INT32 extendee: \"Bar\" }",
3890
3891 "foo.proto: ext: EXTENDEE: Extensions to non-lite types can only be "
3892 "declared in non-lite files. Note that you cannot extend a non-lite "
3893 "type to contain a lite type, but the reverse is allowed.\n");
3894 }
3895
TEST_F(ValidationErrorTest,NoLiteServices)3896 TEST_F(ValidationErrorTest, NoLiteServices) {
3897 BuildFileWithErrors(
3898 "name: \"foo.proto\" "
3899 "options {"
3900 " optimize_for: LITE_RUNTIME"
3901 " cc_generic_services: true"
3902 " java_generic_services: true"
3903 "} "
3904 "service { name: \"Foo\" }",
3905
3906 "foo.proto: Foo: NAME: Files with optimize_for = LITE_RUNTIME cannot "
3907 "define services unless you set both options cc_generic_services and "
3908 "java_generic_sevices to false.\n");
3909
3910 BuildFile(
3911 "name: \"bar.proto\" "
3912 "options {"
3913 " optimize_for: LITE_RUNTIME"
3914 " cc_generic_services: false"
3915 " java_generic_services: false"
3916 "} "
3917 "service { name: \"Bar\" }");
3918 }
3919
TEST_F(ValidationErrorTest,RollbackAfterError)3920 TEST_F(ValidationErrorTest, RollbackAfterError) {
3921 // Build a file which contains every kind of construct but references an
3922 // undefined type. All these constructs will be added to the symbol table
3923 // before the undefined type error is noticed. The DescriptorPool will then
3924 // have to roll everything back.
3925 BuildFileWithErrors(
3926 "name: \"foo.proto\" "
3927 "message_type {"
3928 " name: \"TestMessage\""
3929 " field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 }"
3930 "} "
3931 "enum_type {"
3932 " name: \"TestEnum\""
3933 " value { name:\"BAR\" number:1 }"
3934 "} "
3935 "service {"
3936 " name: \"TestService\""
3937 " method {"
3938 " name: \"Baz\""
3939 " input_type: \"NoSuchType\"" // error
3940 " output_type: \"TestMessage\""
3941 " }"
3942 "}",
3943
3944 "foo.proto: TestService.Baz: INPUT_TYPE: \"NoSuchType\" is not defined.\n"
3945 );
3946
3947 // Make sure that if we build the same file again with the error fixed,
3948 // it works. If the above rollback was incomplete, then some symbols will
3949 // be left defined, and this second attempt will fail since it tries to
3950 // re-define the same symbols.
3951 BuildFile(
3952 "name: \"foo.proto\" "
3953 "message_type {"
3954 " name: \"TestMessage\""
3955 " field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 }"
3956 "} "
3957 "enum_type {"
3958 " name: \"TestEnum\""
3959 " value { name:\"BAR\" number:1 }"
3960 "} "
3961 "service {"
3962 " name: \"TestService\""
3963 " method { name:\"Baz\""
3964 " input_type:\"TestMessage\""
3965 " output_type:\"TestMessage\" }"
3966 "}");
3967 }
3968
TEST_F(ValidationErrorTest,ErrorsReportedToLogError)3969 TEST_F(ValidationErrorTest, ErrorsReportedToLogError) {
3970 // Test that errors are reported to GOOGLE_LOG(ERROR) if no error collector is
3971 // provided.
3972
3973 FileDescriptorProto file_proto;
3974 ASSERT_TRUE(TextFormat::ParseFromString(
3975 "name: \"foo.proto\" "
3976 "message_type { name: \"Foo\" } "
3977 "message_type { name: \"Foo\" } ",
3978 &file_proto));
3979
3980 vector<string> errors;
3981
3982 {
3983 ScopedMemoryLog log;
3984 EXPECT_TRUE(pool_.BuildFile(file_proto) == NULL);
3985 errors = log.GetMessages(ERROR);
3986 }
3987
3988 ASSERT_EQ(2, errors.size());
3989
3990 EXPECT_EQ("Invalid proto descriptor for file \"foo.proto\":", errors[0]);
3991 EXPECT_EQ(" Foo: \"Foo\" is already defined.", errors[1]);
3992 }
3993
TEST_F(ValidationErrorTest,DisallowEnumAlias)3994 TEST_F(ValidationErrorTest, DisallowEnumAlias) {
3995 BuildFileWithErrors(
3996 "name: \"foo.proto\" "
3997 "enum_type {"
3998 " name: \"Bar\""
3999 " value { name:\"ENUM_A\" number:0 }"
4000 " value { name:\"ENUM_B\" number:0 }"
4001 " options { allow_alias: false }"
4002 "}",
4003 "foo.proto: Bar: NUMBER: "
4004 "\"ENUM_B\" uses the same enum value as \"ENUM_A\". "
4005 "If this is intended, set 'option allow_alias = true;' to the enum "
4006 "definition.\n");
4007 }
4008
4009 // ===================================================================
4010 // DescriptorDatabase
4011
AddToDatabase(SimpleDescriptorDatabase * database,const char * file_text)4012 static void AddToDatabase(SimpleDescriptorDatabase* database,
4013 const char* file_text) {
4014 FileDescriptorProto file_proto;
4015 EXPECT_TRUE(TextFormat::ParseFromString(file_text, &file_proto));
4016 database->Add(file_proto);
4017 }
4018
4019 class DatabaseBackedPoolTest : public testing::Test {
4020 protected:
DatabaseBackedPoolTest()4021 DatabaseBackedPoolTest() {}
4022
4023 SimpleDescriptorDatabase database_;
4024
SetUp()4025 virtual void SetUp() {
4026 AddToDatabase(&database_,
4027 "name: 'foo.proto' "
4028 "message_type { name:'Foo' extension_range { start: 1 end: 100 } } "
4029 "enum_type { name:'TestEnum' value { name:'DUMMY' number:0 } } "
4030 "service { name:'TestService' } ");
4031 AddToDatabase(&database_,
4032 "name: 'bar.proto' "
4033 "dependency: 'foo.proto' "
4034 "message_type { name:'Bar' } "
4035 "extension { name:'foo_ext' extendee: '.Foo' number:5 "
4036 " label:LABEL_OPTIONAL type:TYPE_INT32 } ");
4037 // Baz has an undeclared dependency on Foo.
4038 AddToDatabase(&database_,
4039 "name: 'baz.proto' "
4040 "message_type { "
4041 " name:'Baz' "
4042 " field { name:'foo' number:1 label:LABEL_OPTIONAL type_name:'Foo' } "
4043 "}");
4044 }
4045
4046 // We can't inject a file containing errors into a DescriptorPool, so we
4047 // need an actual mock DescriptorDatabase to test errors.
4048 class ErrorDescriptorDatabase : public DescriptorDatabase {
4049 public:
ErrorDescriptorDatabase()4050 ErrorDescriptorDatabase() {}
~ErrorDescriptorDatabase()4051 ~ErrorDescriptorDatabase() {}
4052
4053 // implements DescriptorDatabase ---------------------------------
FindFileByName(const string & filename,FileDescriptorProto * output)4054 bool FindFileByName(const string& filename,
4055 FileDescriptorProto* output) {
4056 // error.proto and error2.proto cyclically import each other.
4057 if (filename == "error.proto") {
4058 output->Clear();
4059 output->set_name("error.proto");
4060 output->add_dependency("error2.proto");
4061 return true;
4062 } else if (filename == "error2.proto") {
4063 output->Clear();
4064 output->set_name("error2.proto");
4065 output->add_dependency("error.proto");
4066 return true;
4067 } else {
4068 return false;
4069 }
4070 }
FindFileContainingSymbol(const string & symbol_name,FileDescriptorProto * output)4071 bool FindFileContainingSymbol(const string& symbol_name,
4072 FileDescriptorProto* output) {
4073 return false;
4074 }
FindFileContainingExtension(const string & containing_type,int field_number,FileDescriptorProto * output)4075 bool FindFileContainingExtension(const string& containing_type,
4076 int field_number,
4077 FileDescriptorProto* output) {
4078 return false;
4079 }
4080 };
4081
4082 // A DescriptorDatabase that counts how many times each method has been
4083 // called and forwards to some other DescriptorDatabase.
4084 class CallCountingDatabase : public DescriptorDatabase {
4085 public:
CallCountingDatabase(DescriptorDatabase * wrapped_db)4086 CallCountingDatabase(DescriptorDatabase* wrapped_db)
4087 : wrapped_db_(wrapped_db) {
4088 Clear();
4089 }
~CallCountingDatabase()4090 ~CallCountingDatabase() {}
4091
4092 DescriptorDatabase* wrapped_db_;
4093
4094 int call_count_;
4095
Clear()4096 void Clear() {
4097 call_count_ = 0;
4098 }
4099
4100 // implements DescriptorDatabase ---------------------------------
FindFileByName(const string & filename,FileDescriptorProto * output)4101 bool FindFileByName(const string& filename,
4102 FileDescriptorProto* output) {
4103 ++call_count_;
4104 return wrapped_db_->FindFileByName(filename, output);
4105 }
FindFileContainingSymbol(const string & symbol_name,FileDescriptorProto * output)4106 bool FindFileContainingSymbol(const string& symbol_name,
4107 FileDescriptorProto* output) {
4108 ++call_count_;
4109 return wrapped_db_->FindFileContainingSymbol(symbol_name, output);
4110 }
FindFileContainingExtension(const string & containing_type,int field_number,FileDescriptorProto * output)4111 bool FindFileContainingExtension(const string& containing_type,
4112 int field_number,
4113 FileDescriptorProto* output) {
4114 ++call_count_;
4115 return wrapped_db_->FindFileContainingExtension(
4116 containing_type, field_number, output);
4117 }
4118 };
4119
4120 // A DescriptorDatabase which falsely always returns foo.proto when searching
4121 // for any symbol or extension number. This shouldn't cause the
4122 // DescriptorPool to reload foo.proto if it is already loaded.
4123 class FalsePositiveDatabase : public DescriptorDatabase {
4124 public:
FalsePositiveDatabase(DescriptorDatabase * wrapped_db)4125 FalsePositiveDatabase(DescriptorDatabase* wrapped_db)
4126 : wrapped_db_(wrapped_db) {}
~FalsePositiveDatabase()4127 ~FalsePositiveDatabase() {}
4128
4129 DescriptorDatabase* wrapped_db_;
4130
4131 // implements DescriptorDatabase ---------------------------------
FindFileByName(const string & filename,FileDescriptorProto * output)4132 bool FindFileByName(const string& filename,
4133 FileDescriptorProto* output) {
4134 return wrapped_db_->FindFileByName(filename, output);
4135 }
FindFileContainingSymbol(const string & symbol_name,FileDescriptorProto * output)4136 bool FindFileContainingSymbol(const string& symbol_name,
4137 FileDescriptorProto* output) {
4138 return FindFileByName("foo.proto", output);
4139 }
FindFileContainingExtension(const string & containing_type,int field_number,FileDescriptorProto * output)4140 bool FindFileContainingExtension(const string& containing_type,
4141 int field_number,
4142 FileDescriptorProto* output) {
4143 return FindFileByName("foo.proto", output);
4144 }
4145 };
4146 };
4147
TEST_F(DatabaseBackedPoolTest,FindFileByName)4148 TEST_F(DatabaseBackedPoolTest, FindFileByName) {
4149 DescriptorPool pool(&database_);
4150
4151 const FileDescriptor* foo = pool.FindFileByName("foo.proto");
4152 ASSERT_TRUE(foo != NULL);
4153 EXPECT_EQ("foo.proto", foo->name());
4154 ASSERT_EQ(1, foo->message_type_count());
4155 EXPECT_EQ("Foo", foo->message_type(0)->name());
4156
4157 EXPECT_EQ(foo, pool.FindFileByName("foo.proto"));
4158
4159 EXPECT_TRUE(pool.FindFileByName("no_such_file.proto") == NULL);
4160 }
4161
TEST_F(DatabaseBackedPoolTest,FindDependencyBeforeDependent)4162 TEST_F(DatabaseBackedPoolTest, FindDependencyBeforeDependent) {
4163 DescriptorPool pool(&database_);
4164
4165 const FileDescriptor* foo = pool.FindFileByName("foo.proto");
4166 ASSERT_TRUE(foo != NULL);
4167 EXPECT_EQ("foo.proto", foo->name());
4168 ASSERT_EQ(1, foo->message_type_count());
4169 EXPECT_EQ("Foo", foo->message_type(0)->name());
4170
4171 const FileDescriptor* bar = pool.FindFileByName("bar.proto");
4172 ASSERT_TRUE(bar != NULL);
4173 EXPECT_EQ("bar.proto", bar->name());
4174 ASSERT_EQ(1, bar->message_type_count());
4175 EXPECT_EQ("Bar", bar->message_type(0)->name());
4176
4177 ASSERT_EQ(1, bar->dependency_count());
4178 EXPECT_EQ(foo, bar->dependency(0));
4179 }
4180
TEST_F(DatabaseBackedPoolTest,FindDependentBeforeDependency)4181 TEST_F(DatabaseBackedPoolTest, FindDependentBeforeDependency) {
4182 DescriptorPool pool(&database_);
4183
4184 const FileDescriptor* bar = pool.FindFileByName("bar.proto");
4185 ASSERT_TRUE(bar != NULL);
4186 EXPECT_EQ("bar.proto", bar->name());
4187 ASSERT_EQ(1, bar->message_type_count());
4188 ASSERT_EQ("Bar", bar->message_type(0)->name());
4189
4190 const FileDescriptor* foo = pool.FindFileByName("foo.proto");
4191 ASSERT_TRUE(foo != NULL);
4192 EXPECT_EQ("foo.proto", foo->name());
4193 ASSERT_EQ(1, foo->message_type_count());
4194 ASSERT_EQ("Foo", foo->message_type(0)->name());
4195
4196 ASSERT_EQ(1, bar->dependency_count());
4197 EXPECT_EQ(foo, bar->dependency(0));
4198 }
4199
TEST_F(DatabaseBackedPoolTest,FindFileContainingSymbol)4200 TEST_F(DatabaseBackedPoolTest, FindFileContainingSymbol) {
4201 DescriptorPool pool(&database_);
4202
4203 const FileDescriptor* file = pool.FindFileContainingSymbol("Foo");
4204 ASSERT_TRUE(file != NULL);
4205 EXPECT_EQ("foo.proto", file->name());
4206 EXPECT_EQ(file, pool.FindFileByName("foo.proto"));
4207
4208 EXPECT_TRUE(pool.FindFileContainingSymbol("NoSuchSymbol") == NULL);
4209 }
4210
TEST_F(DatabaseBackedPoolTest,FindMessageTypeByName)4211 TEST_F(DatabaseBackedPoolTest, FindMessageTypeByName) {
4212 DescriptorPool pool(&database_);
4213
4214 const Descriptor* type = pool.FindMessageTypeByName("Foo");
4215 ASSERT_TRUE(type != NULL);
4216 EXPECT_EQ("Foo", type->name());
4217 EXPECT_EQ(type->file(), pool.FindFileByName("foo.proto"));
4218
4219 EXPECT_TRUE(pool.FindMessageTypeByName("NoSuchType") == NULL);
4220 }
4221
TEST_F(DatabaseBackedPoolTest,FindExtensionByNumber)4222 TEST_F(DatabaseBackedPoolTest, FindExtensionByNumber) {
4223 DescriptorPool pool(&database_);
4224
4225 const Descriptor* foo = pool.FindMessageTypeByName("Foo");
4226 ASSERT_TRUE(foo != NULL);
4227
4228 const FieldDescriptor* extension = pool.FindExtensionByNumber(foo, 5);
4229 ASSERT_TRUE(extension != NULL);
4230 EXPECT_EQ("foo_ext", extension->name());
4231 EXPECT_EQ(extension->file(), pool.FindFileByName("bar.proto"));
4232
4233 EXPECT_TRUE(pool.FindExtensionByNumber(foo, 12) == NULL);
4234 }
4235
TEST_F(DatabaseBackedPoolTest,FindAllExtensions)4236 TEST_F(DatabaseBackedPoolTest, FindAllExtensions) {
4237 DescriptorPool pool(&database_);
4238
4239 const Descriptor* foo = pool.FindMessageTypeByName("Foo");
4240
4241 for (int i = 0; i < 2; ++i) {
4242 // Repeat the lookup twice, to check that we get consistent
4243 // results despite the fallback database lookup mutating the pool.
4244 vector<const FieldDescriptor*> extensions;
4245 pool.FindAllExtensions(foo, &extensions);
4246 ASSERT_EQ(1, extensions.size());
4247 EXPECT_EQ(5, extensions[0]->number());
4248 }
4249 }
4250
TEST_F(DatabaseBackedPoolTest,ErrorWithoutErrorCollector)4251 TEST_F(DatabaseBackedPoolTest, ErrorWithoutErrorCollector) {
4252 ErrorDescriptorDatabase error_database;
4253 DescriptorPool pool(&error_database);
4254
4255 vector<string> errors;
4256
4257 {
4258 ScopedMemoryLog log;
4259 EXPECT_TRUE(pool.FindFileByName("error.proto") == NULL);
4260 errors = log.GetMessages(ERROR);
4261 }
4262
4263 EXPECT_FALSE(errors.empty());
4264 }
4265
TEST_F(DatabaseBackedPoolTest,ErrorWithErrorCollector)4266 TEST_F(DatabaseBackedPoolTest, ErrorWithErrorCollector) {
4267 ErrorDescriptorDatabase error_database;
4268 MockErrorCollector error_collector;
4269 DescriptorPool pool(&error_database, &error_collector);
4270
4271 EXPECT_TRUE(pool.FindFileByName("error.proto") == NULL);
4272 EXPECT_EQ(
4273 "error.proto: error.proto: OTHER: File recursively imports itself: "
4274 "error.proto -> error2.proto -> error.proto\n"
4275 "error2.proto: error2.proto: OTHER: Import \"error.proto\" was not "
4276 "found or had errors.\n"
4277 "error.proto: error.proto: OTHER: Import \"error2.proto\" was not "
4278 "found or had errors.\n",
4279 error_collector.text_);
4280 }
4281
TEST_F(DatabaseBackedPoolTest,UndeclaredDependencyOnUnbuiltType)4282 TEST_F(DatabaseBackedPoolTest, UndeclaredDependencyOnUnbuiltType) {
4283 // Check that we find and report undeclared dependencies on types that exist
4284 // in the descriptor database but that have not not been built yet.
4285 MockErrorCollector error_collector;
4286 DescriptorPool pool(&database_, &error_collector);
4287 EXPECT_TRUE(pool.FindMessageTypeByName("Baz") == NULL);
4288 EXPECT_EQ(
4289 "baz.proto: Baz.foo: TYPE: \"Foo\" seems to be defined in \"foo.proto\", "
4290 "which is not imported by \"baz.proto\". To use it here, please add "
4291 "the necessary import.\n",
4292 error_collector.text_);
4293 }
4294
TEST_F(DatabaseBackedPoolTest,RollbackAfterError)4295 TEST_F(DatabaseBackedPoolTest, RollbackAfterError) {
4296 // Make sure that all traces of bad types are removed from the pool. This used
4297 // to be b/4529436, due to the fact that a symbol resolution failure could
4298 // potentially cause another file to be recursively built, which would trigger
4299 // a checkpoint _past_ possibly invalid symbols.
4300 // Baz is defined in the database, but the file is invalid because it is
4301 // missing a necessary import.
4302 DescriptorPool pool(&database_);
4303 EXPECT_TRUE(pool.FindMessageTypeByName("Baz") == NULL);
4304 // Make sure that searching again for the file or the type fails.
4305 EXPECT_TRUE(pool.FindFileByName("baz.proto") == NULL);
4306 EXPECT_TRUE(pool.FindMessageTypeByName("Baz") == NULL);
4307 }
4308
TEST_F(DatabaseBackedPoolTest,UnittestProto)4309 TEST_F(DatabaseBackedPoolTest, UnittestProto) {
4310 // Try to load all of unittest.proto from a DescriptorDatabase. This should
4311 // thoroughly test all paths through DescriptorBuilder to insure that there
4312 // are no deadlocking problems when pool_->mutex_ is non-NULL.
4313 const FileDescriptor* original_file =
4314 protobuf_unittest::TestAllTypes::descriptor()->file();
4315
4316 DescriptorPoolDatabase database(*DescriptorPool::generated_pool());
4317 DescriptorPool pool(&database);
4318 const FileDescriptor* file_from_database =
4319 pool.FindFileByName(original_file->name());
4320
4321 ASSERT_TRUE(file_from_database != NULL);
4322
4323 FileDescriptorProto original_file_proto;
4324 original_file->CopyTo(&original_file_proto);
4325
4326 FileDescriptorProto file_from_database_proto;
4327 file_from_database->CopyTo(&file_from_database_proto);
4328
4329 EXPECT_EQ(original_file_proto.DebugString(),
4330 file_from_database_proto.DebugString());
4331 }
4332
TEST_F(DatabaseBackedPoolTest,DoesntRetryDbUnnecessarily)4333 TEST_F(DatabaseBackedPoolTest, DoesntRetryDbUnnecessarily) {
4334 // Searching for a child of an existing descriptor should never fall back
4335 // to the DescriptorDatabase even if it isn't found, because we know all
4336 // children are already loaded.
4337 CallCountingDatabase call_counter(&database_);
4338 DescriptorPool pool(&call_counter);
4339
4340 const FileDescriptor* file = pool.FindFileByName("foo.proto");
4341 ASSERT_TRUE(file != NULL);
4342 const Descriptor* foo = pool.FindMessageTypeByName("Foo");
4343 ASSERT_TRUE(foo != NULL);
4344 const EnumDescriptor* test_enum = pool.FindEnumTypeByName("TestEnum");
4345 ASSERT_TRUE(test_enum != NULL);
4346 const ServiceDescriptor* test_service = pool.FindServiceByName("TestService");
4347 ASSERT_TRUE(test_service != NULL);
4348
4349 EXPECT_NE(0, call_counter.call_count_);
4350 call_counter.Clear();
4351
4352 EXPECT_TRUE(foo->FindFieldByName("no_such_field") == NULL);
4353 EXPECT_TRUE(foo->FindExtensionByName("no_such_extension") == NULL);
4354 EXPECT_TRUE(foo->FindNestedTypeByName("NoSuchMessageType") == NULL);
4355 EXPECT_TRUE(foo->FindEnumTypeByName("NoSuchEnumType") == NULL);
4356 EXPECT_TRUE(foo->FindEnumValueByName("NO_SUCH_VALUE") == NULL);
4357 EXPECT_TRUE(test_enum->FindValueByName("NO_SUCH_VALUE") == NULL);
4358 EXPECT_TRUE(test_service->FindMethodByName("NoSuchMethod") == NULL);
4359
4360 EXPECT_TRUE(file->FindMessageTypeByName("NoSuchMessageType") == NULL);
4361 EXPECT_TRUE(file->FindEnumTypeByName("NoSuchEnumType") == NULL);
4362 EXPECT_TRUE(file->FindEnumValueByName("NO_SUCH_VALUE") == NULL);
4363 EXPECT_TRUE(file->FindServiceByName("NO_SUCH_VALUE") == NULL);
4364 EXPECT_TRUE(file->FindExtensionByName("no_such_extension") == NULL);
4365
4366 EXPECT_TRUE(pool.FindFileContainingSymbol("Foo.no.such.field") == NULL);
4367 EXPECT_TRUE(pool.FindFileContainingSymbol("Foo.no_such_field") == NULL);
4368 EXPECT_TRUE(pool.FindMessageTypeByName("Foo.NoSuchMessageType") == NULL);
4369 EXPECT_TRUE(pool.FindFieldByName("Foo.no_such_field") == NULL);
4370 EXPECT_TRUE(pool.FindExtensionByName("Foo.no_such_extension") == NULL);
4371 EXPECT_TRUE(pool.FindEnumTypeByName("Foo.NoSuchEnumType") == NULL);
4372 EXPECT_TRUE(pool.FindEnumValueByName("Foo.NO_SUCH_VALUE") == NULL);
4373 EXPECT_TRUE(pool.FindMethodByName("TestService.NoSuchMethod") == NULL);
4374
4375 EXPECT_EQ(0, call_counter.call_count_);
4376 }
4377
TEST_F(DatabaseBackedPoolTest,DoesntReloadFilesUncesessarily)4378 TEST_F(DatabaseBackedPoolTest, DoesntReloadFilesUncesessarily) {
4379 // If FindFileContainingSymbol() or FindFileContainingExtension() return a
4380 // file that is already in the DescriptorPool, it should not attempt to
4381 // reload the file.
4382 FalsePositiveDatabase false_positive_database(&database_);
4383 MockErrorCollector error_collector;
4384 DescriptorPool pool(&false_positive_database, &error_collector);
4385
4386 // First make sure foo.proto is loaded.
4387 const Descriptor* foo = pool.FindMessageTypeByName("Foo");
4388 ASSERT_TRUE(foo != NULL);
4389
4390 // Try inducing false positives.
4391 EXPECT_TRUE(pool.FindMessageTypeByName("NoSuchSymbol") == NULL);
4392 EXPECT_TRUE(pool.FindExtensionByNumber(foo, 22) == NULL);
4393
4394 // No errors should have been reported. (If foo.proto was incorrectly
4395 // loaded multiple times, errors would have been reported.)
4396 EXPECT_EQ("", error_collector.text_);
4397 }
4398
TEST_F(DatabaseBackedPoolTest,DoesntReloadKnownBadFiles)4399 TEST_F(DatabaseBackedPoolTest, DoesntReloadKnownBadFiles) {
4400 ErrorDescriptorDatabase error_database;
4401 MockErrorCollector error_collector;
4402 DescriptorPool pool(&error_database, &error_collector);
4403
4404 EXPECT_TRUE(pool.FindFileByName("error.proto") == NULL);
4405 error_collector.text_.clear();
4406 EXPECT_TRUE(pool.FindFileByName("error.proto") == NULL);
4407 EXPECT_EQ("", error_collector.text_);
4408 }
4409
TEST_F(DatabaseBackedPoolTest,DoesntFallbackOnWrongType)4410 TEST_F(DatabaseBackedPoolTest, DoesntFallbackOnWrongType) {
4411 // If a lookup finds a symbol of the wrong type (e.g. we pass a type name
4412 // to FindFieldByName()), we should fail fast, without checking the fallback
4413 // database.
4414 CallCountingDatabase call_counter(&database_);
4415 DescriptorPool pool(&call_counter);
4416
4417 const FileDescriptor* file = pool.FindFileByName("foo.proto");
4418 ASSERT_TRUE(file != NULL);
4419 const Descriptor* foo = pool.FindMessageTypeByName("Foo");
4420 ASSERT_TRUE(foo != NULL);
4421 const EnumDescriptor* test_enum = pool.FindEnumTypeByName("TestEnum");
4422 ASSERT_TRUE(test_enum != NULL);
4423
4424 EXPECT_NE(0, call_counter.call_count_);
4425 call_counter.Clear();
4426
4427 EXPECT_TRUE(pool.FindMessageTypeByName("TestEnum") == NULL);
4428 EXPECT_TRUE(pool.FindFieldByName("Foo") == NULL);
4429 EXPECT_TRUE(pool.FindExtensionByName("Foo") == NULL);
4430 EXPECT_TRUE(pool.FindEnumTypeByName("Foo") == NULL);
4431 EXPECT_TRUE(pool.FindEnumValueByName("Foo") == NULL);
4432 EXPECT_TRUE(pool.FindServiceByName("Foo") == NULL);
4433 EXPECT_TRUE(pool.FindMethodByName("Foo") == NULL);
4434
4435 EXPECT_EQ(0, call_counter.call_count_);
4436 }
4437
4438 // ===================================================================
4439
4440 class AbortingErrorCollector : public DescriptorPool::ErrorCollector {
4441 public:
AbortingErrorCollector()4442 AbortingErrorCollector() {}
4443
AddError(const string & filename,const string & element_name,const Message * message,ErrorLocation location,const string & error_message)4444 virtual void AddError(
4445 const string &filename,
4446 const string &element_name,
4447 const Message *message,
4448 ErrorLocation location,
4449 const string &error_message) {
4450 GOOGLE_LOG(FATAL) << "AddError() called unexpectedly: " << filename << ": "
4451 << error_message;
4452 }
4453 private:
4454 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(AbortingErrorCollector);
4455 };
4456
4457 // A source tree containing only one file.
4458 class SingletonSourceTree : public compiler::SourceTree {
4459 public:
SingletonSourceTree(const string & filename,const string & contents)4460 SingletonSourceTree(const string& filename, const string& contents)
4461 : filename_(filename), contents_(contents) {}
4462
Open(const string & filename)4463 virtual io::ZeroCopyInputStream* Open(const string& filename) {
4464 return filename == filename_ ?
4465 new io::ArrayInputStream(contents_.data(), contents_.size()) : NULL;
4466 }
4467
4468 private:
4469 const string filename_;
4470 const string contents_;
4471
4472 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SingletonSourceTree);
4473 };
4474
4475 const char *const kSourceLocationTestInput =
4476 "syntax = \"proto2\";\n"
4477 "message A {\n"
4478 " optional int32 a = 1;\n"
4479 " message B {\n"
4480 " required double b = 1;\n"
4481 " }\n"
4482 "}\n"
4483 "enum Indecision {\n"
4484 " YES = 1;\n"
4485 " NO = 2;\n"
4486 " MAYBE = 3;\n"
4487 "}\n"
4488 "service S {\n"
4489 " rpc Method(A) returns (A.B);\n"
4490 // Put an empty line here to make the source location range match.
4491 "\n"
4492 "}\n";
4493
4494 class SourceLocationTest : public testing::Test {
4495 public:
SourceLocationTest()4496 SourceLocationTest()
4497 : source_tree_("/test/test.proto", kSourceLocationTestInput),
4498 db_(&source_tree_),
4499 pool_(&db_, &collector_) {}
4500
PrintSourceLocation(const SourceLocation & loc)4501 static string PrintSourceLocation(const SourceLocation &loc) {
4502 return strings::Substitute("$0:$1-$2:$3",
4503 1 + loc.start_line,
4504 1 + loc.start_column,
4505 1 + loc.end_line,
4506 1 + loc.end_column);
4507 }
4508
4509 private:
4510 AbortingErrorCollector collector_;
4511 SingletonSourceTree source_tree_;
4512 compiler::SourceTreeDescriptorDatabase db_;
4513
4514 protected:
4515 DescriptorPool pool_;
4516 };
4517
4518 // TODO(adonovan): implement support for option fields and for
4519 // subparts of declarations.
4520
TEST_F(SourceLocationTest,GetSourceLocation)4521 TEST_F(SourceLocationTest, GetSourceLocation) {
4522 SourceLocation loc;
4523
4524 const FileDescriptor *file_desc =
4525 GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto"));
4526
4527 const Descriptor *a_desc = file_desc->FindMessageTypeByName("A");
4528 EXPECT_TRUE(a_desc->GetSourceLocation(&loc));
4529 EXPECT_EQ("2:1-7:2", PrintSourceLocation(loc));
4530
4531 const Descriptor *a_b_desc = a_desc->FindNestedTypeByName("B");
4532 EXPECT_TRUE(a_b_desc->GetSourceLocation(&loc));
4533 EXPECT_EQ("4:3-6:4", PrintSourceLocation(loc));
4534
4535 const EnumDescriptor *e_desc = file_desc->FindEnumTypeByName("Indecision");
4536 EXPECT_TRUE(e_desc->GetSourceLocation(&loc));
4537 EXPECT_EQ("8:1-12:2", PrintSourceLocation(loc));
4538
4539 const EnumValueDescriptor *yes_desc = e_desc->FindValueByName("YES");
4540 EXPECT_TRUE(yes_desc->GetSourceLocation(&loc));
4541 EXPECT_EQ("9:3-9:13", PrintSourceLocation(loc));
4542
4543 const ServiceDescriptor *s_desc = file_desc->FindServiceByName("S");
4544 EXPECT_TRUE(s_desc->GetSourceLocation(&loc));
4545 EXPECT_EQ("13:1-16:2", PrintSourceLocation(loc));
4546
4547 const MethodDescriptor *m_desc = s_desc->FindMethodByName("Method");
4548 EXPECT_TRUE(m_desc->GetSourceLocation(&loc));
4549 EXPECT_EQ("14:3-14:31", PrintSourceLocation(loc));
4550
4551 }
4552
4553 // Missing SourceCodeInfo doesn't cause crash:
TEST_F(SourceLocationTest,GetSourceLocation_MissingSourceCodeInfo)4554 TEST_F(SourceLocationTest, GetSourceLocation_MissingSourceCodeInfo) {
4555 SourceLocation loc;
4556
4557 const FileDescriptor *file_desc =
4558 GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto"));
4559
4560 FileDescriptorProto proto;
4561 file_desc->CopyTo(&proto); // Note, this discards the SourceCodeInfo.
4562 EXPECT_FALSE(proto.has_source_code_info());
4563
4564 DescriptorPool bad1_pool(&pool_);
4565 const FileDescriptor* bad1_file_desc =
4566 GOOGLE_CHECK_NOTNULL(bad1_pool.BuildFile(proto));
4567 const Descriptor *bad1_a_desc = bad1_file_desc->FindMessageTypeByName("A");
4568 EXPECT_FALSE(bad1_a_desc->GetSourceLocation(&loc));
4569 }
4570
4571 // Corrupt SourceCodeInfo doesn't cause crash:
TEST_F(SourceLocationTest,GetSourceLocation_BogusSourceCodeInfo)4572 TEST_F(SourceLocationTest, GetSourceLocation_BogusSourceCodeInfo) {
4573 SourceLocation loc;
4574
4575 const FileDescriptor *file_desc =
4576 GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto"));
4577
4578 FileDescriptorProto proto;
4579 file_desc->CopyTo(&proto); // Note, this discards the SourceCodeInfo.
4580 EXPECT_FALSE(proto.has_source_code_info());
4581 SourceCodeInfo_Location *loc_msg =
4582 proto.mutable_source_code_info()->add_location();
4583 loc_msg->add_path(1);
4584 loc_msg->add_path(2);
4585 loc_msg->add_path(3);
4586 loc_msg->add_span(4);
4587 loc_msg->add_span(5);
4588 loc_msg->add_span(6);
4589
4590 DescriptorPool bad2_pool(&pool_);
4591 const FileDescriptor* bad2_file_desc =
4592 GOOGLE_CHECK_NOTNULL(bad2_pool.BuildFile(proto));
4593 const Descriptor *bad2_a_desc = bad2_file_desc->FindMessageTypeByName("A");
4594 EXPECT_FALSE(bad2_a_desc->GetSourceLocation(&loc));
4595 }
4596
4597 // ===================================================================
4598
4599 const char* const kCopySourceCodeInfoToTestInput =
4600 "syntax = \"proto2\";\n"
4601 "message Foo {}\n";
4602
4603 // Required since source code information is not preserved by
4604 // FileDescriptorTest.
4605 class CopySourceCodeInfoToTest : public testing::Test {
4606 public:
CopySourceCodeInfoToTest()4607 CopySourceCodeInfoToTest()
4608 : source_tree_("/test/test.proto", kCopySourceCodeInfoToTestInput),
4609 db_(&source_tree_),
4610 pool_(&db_, &collector_) {}
4611
4612 private:
4613 AbortingErrorCollector collector_;
4614 SingletonSourceTree source_tree_;
4615 compiler::SourceTreeDescriptorDatabase db_;
4616
4617 protected:
4618 DescriptorPool pool_;
4619 };
4620
TEST_F(CopySourceCodeInfoToTest,CopyTo_DoesNotCopySourceCodeInfo)4621 TEST_F(CopySourceCodeInfoToTest, CopyTo_DoesNotCopySourceCodeInfo) {
4622 const FileDescriptor* file_desc =
4623 GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto"));
4624 FileDescriptorProto file_desc_proto;
4625 ASSERT_FALSE(file_desc_proto.has_source_code_info());
4626
4627 file_desc->CopyTo(&file_desc_proto);
4628 EXPECT_FALSE(file_desc_proto.has_source_code_info());
4629 }
4630
TEST_F(CopySourceCodeInfoToTest,CopySourceCodeInfoTo)4631 TEST_F(CopySourceCodeInfoToTest, CopySourceCodeInfoTo) {
4632 const FileDescriptor* file_desc =
4633 GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto"));
4634 FileDescriptorProto file_desc_proto;
4635 ASSERT_FALSE(file_desc_proto.has_source_code_info());
4636
4637 file_desc->CopySourceCodeInfoTo(&file_desc_proto);
4638 const SourceCodeInfo& info = file_desc_proto.source_code_info();
4639 ASSERT_EQ(3, info.location_size());
4640 // Get the Foo message location
4641 const SourceCodeInfo_Location& foo_location = info.location(1);
4642 ASSERT_EQ(2, foo_location.path_size());
4643 EXPECT_EQ(FileDescriptorProto::kMessageTypeFieldNumber, foo_location.path(0));
4644 EXPECT_EQ(0, foo_location.path(1)); // Foo is the first message defined
4645 ASSERT_EQ(3, foo_location.span_size()); // Foo spans one line
4646 EXPECT_EQ(1, foo_location.span(0)); // Foo is declared on line 1
4647 EXPECT_EQ(0, foo_location.span(1)); // Foo starts at column 0
4648 EXPECT_EQ(14, foo_location.span(2)); // Foo ends on column 14
4649 }
4650
4651 // ===================================================================
4652
4653
4654 } // namespace descriptor_unittest
4655 } // namespace protobuf
4656 } // namespace google
4657