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