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