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