blob: 55aebfd1226ca4c8d9127053e0fc2ee9e1f9b589 [file] [log] [blame]
temporal40ee5512008-07-10 02:12:20 +00001// Protocol Buffers - Google's data interchange format
kenton@google.com24bf56f2008-09-24 20:31:01 +00002// Copyright 2008 Google Inc. All rights reserved.
temporal40ee5512008-07-10 02:12:20 +00003// http://code.google.com/p/protobuf/
4//
kenton@google.com24bf56f2008-09-24 20:31:01 +00005// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
temporal40ee5512008-07-10 02:12:20 +00008//
kenton@google.com24bf56f2008-09-24 20:31:01 +00009// * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11// * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15// * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
temporal40ee5512008-07-10 02:12:20 +000018//
kenton@google.com24bf56f2008-09-24 20:31:01 +000019// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
temporal40ee5512008-07-10 02:12:20 +000030
31// Author: kenton@google.com (Kenton Varda)
32// Based on original Protocol Buffers design by
33// Sanjay Ghemawat, Jeff Dean, and others.
34//
35// This file makes extensive use of RFC 3092. :)
36
37#include <vector>
38
39#include <google/protobuf/descriptor.h>
40#include <google/protobuf/descriptor_database.h>
kenton@google.com24bf56f2008-09-24 20:31:01 +000041#include <google/protobuf/dynamic_message.h>
temporal40ee5512008-07-10 02:12:20 +000042#include <google/protobuf/descriptor.pb.h>
43#include <google/protobuf/text_format.h>
44#include <google/protobuf/unittest.pb.h>
kenton@google.com24bf56f2008-09-24 20:31:01 +000045#include <google/protobuf/unittest_custom_options.pb.h>
temporal40ee5512008-07-10 02:12:20 +000046#include <google/protobuf/stubs/strutil.h>
47#include <google/protobuf/stubs/substitute.h>
48
49#include <google/protobuf/stubs/common.h>
50#include <google/protobuf/testing/googletest.h>
51#include <gtest/gtest.h>
52
53namespace google {
54namespace protobuf {
55
kenton@google.com2d6daa72009-01-22 01:27:00 +000056// Can't use an anonymous namespace here due to brokenness of Tru64 compiler.
57namespace descriptor_unittest {
temporal40ee5512008-07-10 02:12:20 +000058
59// Some helpers to make assembling descriptors faster.
60DescriptorProto* AddMessage(FileDescriptorProto* file, const string& name) {
61 DescriptorProto* result = file->add_message_type();
62 result->set_name(name);
63 return result;
64}
65
66DescriptorProto* AddNestedMessage(DescriptorProto* parent, const string& name) {
67 DescriptorProto* result = parent->add_nested_type();
68 result->set_name(name);
69 return result;
70}
71
72EnumDescriptorProto* AddEnum(FileDescriptorProto* file, const string& name) {
73 EnumDescriptorProto* result = file->add_enum_type();
74 result->set_name(name);
75 return result;
76}
77
78EnumDescriptorProto* AddNestedEnum(DescriptorProto* parent,
79 const string& name) {
80 EnumDescriptorProto* result = parent->add_enum_type();
81 result->set_name(name);
82 return result;
83}
84
85ServiceDescriptorProto* AddService(FileDescriptorProto* file,
86 const string& name) {
87 ServiceDescriptorProto* result = file->add_service();
88 result->set_name(name);
89 return result;
90}
91
92FieldDescriptorProto* AddField(DescriptorProto* parent,
93 const string& name, int number,
94 FieldDescriptorProto::Label label,
95 FieldDescriptorProto::Type type) {
96 FieldDescriptorProto* result = parent->add_field();
97 result->set_name(name);
98 result->set_number(number);
99 result->set_label(label);
100 result->set_type(type);
101 return result;
102}
103
104FieldDescriptorProto* AddExtension(FileDescriptorProto* file,
105 const string& extendee,
106 const string& name, int number,
107 FieldDescriptorProto::Label label,
108 FieldDescriptorProto::Type type) {
109 FieldDescriptorProto* result = file->add_extension();
110 result->set_name(name);
111 result->set_number(number);
112 result->set_label(label);
113 result->set_type(type);
114 result->set_extendee(extendee);
115 return result;
116}
117
118FieldDescriptorProto* AddNestedExtension(DescriptorProto* parent,
119 const string& extendee,
120 const string& name, int number,
121 FieldDescriptorProto::Label label,
122 FieldDescriptorProto::Type type) {
123 FieldDescriptorProto* result = parent->add_extension();
124 result->set_name(name);
125 result->set_number(number);
126 result->set_label(label);
127 result->set_type(type);
128 result->set_extendee(extendee);
129 return result;
130}
131
132DescriptorProto::ExtensionRange* AddExtensionRange(DescriptorProto* parent,
133 int start, int end) {
134 DescriptorProto::ExtensionRange* result = parent->add_extension_range();
135 result->set_start(start);
136 result->set_end(end);
137 return result;
138}
139
140EnumValueDescriptorProto* AddEnumValue(EnumDescriptorProto* enum_proto,
141 const string& name, int number) {
142 EnumValueDescriptorProto* result = enum_proto->add_value();
143 result->set_name(name);
144 result->set_number(number);
145 return result;
146}
147
148MethodDescriptorProto* AddMethod(ServiceDescriptorProto* service,
149 const string& name,
150 const string& input_type,
151 const string& output_type) {
152 MethodDescriptorProto* result = service->add_method();
153 result->set_name(name);
154 result->set_input_type(input_type);
155 result->set_output_type(output_type);
156 return result;
157}
158
159// Empty enums technically aren't allowed. We need to insert a dummy value
160// into them.
161void AddEmptyEnum(FileDescriptorProto* file, const string& name) {
162 AddEnumValue(AddEnum(file, name), name + "_DUMMY", 1);
163}
164
165// ===================================================================
166
167// Test simple files.
168class FileDescriptorTest : public testing::Test {
169 protected:
170 virtual void SetUp() {
171 // Build descriptors for the following definitions:
172 //
173 // // in "foo.proto"
174 // message FooMessage { extensions 1; }
175 // enum FooEnum {FOO_ENUM_VALUE = 1;}
176 // service FooService {}
177 // extend FooMessage { optional int32 foo_extension = 1; }
178 //
179 // // in "bar.proto"
180 // package bar_package;
181 // message BarMessage { extensions 1; }
182 // enum BarEnum {BAR_ENUM_VALUE = 1;}
183 // service BarService {}
184 // extend BarMessage { optional int32 bar_extension = 1; }
185 //
186 // Also, we have an empty file "baz.proto". This file's purpose is to
187 // make sure that even though it has the same package as foo.proto,
188 // searching it for members of foo.proto won't work.
189
190 FileDescriptorProto foo_file;
191 foo_file.set_name("foo.proto");
192 AddExtensionRange(AddMessage(&foo_file, "FooMessage"), 1, 2);
193 AddEnumValue(AddEnum(&foo_file, "FooEnum"), "FOO_ENUM_VALUE", 1);
194 AddService(&foo_file, "FooService");
195 AddExtension(&foo_file, "FooMessage", "foo_extension", 1,
196 FieldDescriptorProto::LABEL_OPTIONAL,
197 FieldDescriptorProto::TYPE_INT32);
198
199 FileDescriptorProto bar_file;
200 bar_file.set_name("bar.proto");
201 bar_file.set_package("bar_package");
202 bar_file.add_dependency("foo.proto");
203 AddExtensionRange(AddMessage(&bar_file, "BarMessage"), 1, 2);
204 AddEnumValue(AddEnum(&bar_file, "BarEnum"), "BAR_ENUM_VALUE", 1);
205 AddService(&bar_file, "BarService");
206 AddExtension(&bar_file, "bar_package.BarMessage", "bar_extension", 1,
207 FieldDescriptorProto::LABEL_OPTIONAL,
208 FieldDescriptorProto::TYPE_INT32);
209
210 FileDescriptorProto baz_file;
211 baz_file.set_name("baz.proto");
212
213 // Build the descriptors and get the pointers.
214 foo_file_ = pool_.BuildFile(foo_file);
215 ASSERT_TRUE(foo_file_ != NULL);
216
217 bar_file_ = pool_.BuildFile(bar_file);
218 ASSERT_TRUE(bar_file_ != NULL);
219
220 baz_file_ = pool_.BuildFile(baz_file);
221 ASSERT_TRUE(baz_file_ != NULL);
222
223 ASSERT_EQ(1, foo_file_->message_type_count());
224 foo_message_ = foo_file_->message_type(0);
225 ASSERT_EQ(1, foo_file_->enum_type_count());
226 foo_enum_ = foo_file_->enum_type(0);
227 ASSERT_EQ(1, foo_enum_->value_count());
228 foo_enum_value_ = foo_enum_->value(0);
229 ASSERT_EQ(1, foo_file_->service_count());
230 foo_service_ = foo_file_->service(0);
231 ASSERT_EQ(1, foo_file_->extension_count());
232 foo_extension_ = foo_file_->extension(0);
233
234 ASSERT_EQ(1, bar_file_->message_type_count());
235 bar_message_ = bar_file_->message_type(0);
236 ASSERT_EQ(1, bar_file_->enum_type_count());
237 bar_enum_ = bar_file_->enum_type(0);
238 ASSERT_EQ(1, bar_enum_->value_count());
239 bar_enum_value_ = bar_enum_->value(0);
240 ASSERT_EQ(1, bar_file_->service_count());
241 bar_service_ = bar_file_->service(0);
242 ASSERT_EQ(1, bar_file_->extension_count());
243 bar_extension_ = bar_file_->extension(0);
244 }
245
246 DescriptorPool pool_;
247
248 const FileDescriptor* foo_file_;
249 const FileDescriptor* bar_file_;
250 const FileDescriptor* baz_file_;
251
252 const Descriptor* foo_message_;
253 const EnumDescriptor* foo_enum_;
254 const EnumValueDescriptor* foo_enum_value_;
255 const ServiceDescriptor* foo_service_;
256 const FieldDescriptor* foo_extension_;
257
258 const Descriptor* bar_message_;
259 const EnumDescriptor* bar_enum_;
260 const EnumValueDescriptor* bar_enum_value_;
261 const ServiceDescriptor* bar_service_;
262 const FieldDescriptor* bar_extension_;
263};
264
265TEST_F(FileDescriptorTest, Name) {
266 EXPECT_EQ("foo.proto", foo_file_->name());
267 EXPECT_EQ("bar.proto", bar_file_->name());
268 EXPECT_EQ("baz.proto", baz_file_->name());
269}
270
271TEST_F(FileDescriptorTest, Package) {
272 EXPECT_EQ("", foo_file_->package());
273 EXPECT_EQ("bar_package", bar_file_->package());
274}
275
276TEST_F(FileDescriptorTest, Dependencies) {
277 EXPECT_EQ(0, foo_file_->dependency_count());
278 EXPECT_EQ(1, bar_file_->dependency_count());
279 EXPECT_EQ(foo_file_, bar_file_->dependency(0));
280}
281
282TEST_F(FileDescriptorTest, FindMessageTypeByName) {
283 EXPECT_EQ(foo_message_, foo_file_->FindMessageTypeByName("FooMessage"));
284 EXPECT_EQ(bar_message_, bar_file_->FindMessageTypeByName("BarMessage"));
285
286 EXPECT_TRUE(foo_file_->FindMessageTypeByName("BarMessage") == NULL);
287 EXPECT_TRUE(bar_file_->FindMessageTypeByName("FooMessage") == NULL);
288 EXPECT_TRUE(baz_file_->FindMessageTypeByName("FooMessage") == NULL);
289
290 EXPECT_TRUE(foo_file_->FindMessageTypeByName("NoSuchMessage") == NULL);
291 EXPECT_TRUE(foo_file_->FindMessageTypeByName("FooEnum") == NULL);
292}
293
294TEST_F(FileDescriptorTest, FindEnumTypeByName) {
295 EXPECT_EQ(foo_enum_, foo_file_->FindEnumTypeByName("FooEnum"));
296 EXPECT_EQ(bar_enum_, bar_file_->FindEnumTypeByName("BarEnum"));
297
298 EXPECT_TRUE(foo_file_->FindEnumTypeByName("BarEnum") == NULL);
299 EXPECT_TRUE(bar_file_->FindEnumTypeByName("FooEnum") == NULL);
300 EXPECT_TRUE(baz_file_->FindEnumTypeByName("FooEnum") == NULL);
301
302 EXPECT_TRUE(foo_file_->FindEnumTypeByName("NoSuchEnum") == NULL);
303 EXPECT_TRUE(foo_file_->FindEnumTypeByName("FooMessage") == NULL);
304}
305
306TEST_F(FileDescriptorTest, FindEnumValueByName) {
307 EXPECT_EQ(foo_enum_value_, foo_file_->FindEnumValueByName("FOO_ENUM_VALUE"));
308 EXPECT_EQ(bar_enum_value_, bar_file_->FindEnumValueByName("BAR_ENUM_VALUE"));
309
310 EXPECT_TRUE(foo_file_->FindEnumValueByName("BAR_ENUM_VALUE") == NULL);
311 EXPECT_TRUE(bar_file_->FindEnumValueByName("FOO_ENUM_VALUE") == NULL);
312 EXPECT_TRUE(baz_file_->FindEnumValueByName("FOO_ENUM_VALUE") == NULL);
313
314 EXPECT_TRUE(foo_file_->FindEnumValueByName("NO_SUCH_VALUE") == NULL);
315 EXPECT_TRUE(foo_file_->FindEnumValueByName("FooMessage") == NULL);
316}
317
318TEST_F(FileDescriptorTest, FindServiceByName) {
319 EXPECT_EQ(foo_service_, foo_file_->FindServiceByName("FooService"));
320 EXPECT_EQ(bar_service_, bar_file_->FindServiceByName("BarService"));
321
322 EXPECT_TRUE(foo_file_->FindServiceByName("BarService") == NULL);
323 EXPECT_TRUE(bar_file_->FindServiceByName("FooService") == NULL);
324 EXPECT_TRUE(baz_file_->FindServiceByName("FooService") == NULL);
325
326 EXPECT_TRUE(foo_file_->FindServiceByName("NoSuchService") == NULL);
327 EXPECT_TRUE(foo_file_->FindServiceByName("FooMessage") == NULL);
328}
329
330TEST_F(FileDescriptorTest, FindExtensionByName) {
331 EXPECT_EQ(foo_extension_, foo_file_->FindExtensionByName("foo_extension"));
332 EXPECT_EQ(bar_extension_, bar_file_->FindExtensionByName("bar_extension"));
333
334 EXPECT_TRUE(foo_file_->FindExtensionByName("bar_extension") == NULL);
335 EXPECT_TRUE(bar_file_->FindExtensionByName("foo_extension") == NULL);
336 EXPECT_TRUE(baz_file_->FindExtensionByName("foo_extension") == NULL);
337
338 EXPECT_TRUE(foo_file_->FindExtensionByName("no_such_extension") == NULL);
339 EXPECT_TRUE(foo_file_->FindExtensionByName("FooMessage") == NULL);
340}
341
342TEST_F(FileDescriptorTest, FindExtensionByNumber) {
343 EXPECT_EQ(foo_extension_, pool_.FindExtensionByNumber(foo_message_, 1));
344 EXPECT_EQ(bar_extension_, pool_.FindExtensionByNumber(bar_message_, 1));
345
346 EXPECT_TRUE(pool_.FindExtensionByNumber(foo_message_, 2) == NULL);
347}
348
kenton@google.comd37d46d2009-04-25 02:53:47 +0000349TEST_F(FileDescriptorTest, BuildAgain) {
350 // Test that if te call BuildFile again on the same input we get the same
351 // FileDescriptor back.
352 FileDescriptorProto file;
353 foo_file_->CopyTo(&file);
354 EXPECT_EQ(foo_file_, pool_.BuildFile(file));
355
356 // But if we change the file then it won't work.
357 file.set_package("some.other.package");
358 EXPECT_TRUE(pool_.BuildFile(file) == NULL);
359}
360
temporal40ee5512008-07-10 02:12:20 +0000361// ===================================================================
362
363// Test simple flat messages and fields.
364class DescriptorTest : public testing::Test {
365 protected:
366 virtual void SetUp() {
367 // Build descriptors for the following definitions:
368 //
369 // // in "foo.proto"
370 // message TestForeign {}
371 // enum TestEnum {}
372 //
373 // message TestMessage {
374 // required string foo = 1;
375 // optional TestEnum bar = 6;
376 // repeated TestForeign baz = 500000000;
377 // optional group qux = 15 {}
378 // }
379 //
380 // // in "bar.proto"
381 // package corge.grault;
382 // message TestMessage2 {
383 // required string foo = 1;
384 // required string bar = 2;
385 // required string quux = 6;
386 // }
387 //
388 // We cheat and use TestForeign as the type for qux rather than create
389 // an actual nested type.
390 //
391 // Since all primitive types (including string) use the same building
392 // code, there's no need to test each one individually.
393 //
394 // TestMessage2 is primarily here to test FindFieldByName and friends.
395 // All messages created from the same DescriptorPool share the same lookup
396 // table, so we need to insure that they don't interfere.
397
398 FileDescriptorProto foo_file;
399 foo_file.set_name("foo.proto");
400 AddMessage(&foo_file, "TestForeign");
401 AddEmptyEnum(&foo_file, "TestEnum");
402
403 DescriptorProto* message = AddMessage(&foo_file, "TestMessage");
404 AddField(message, "foo", 1,
405 FieldDescriptorProto::LABEL_REQUIRED,
406 FieldDescriptorProto::TYPE_STRING);
407 AddField(message, "bar", 6,
408 FieldDescriptorProto::LABEL_OPTIONAL,
409 FieldDescriptorProto::TYPE_ENUM)
410 ->set_type_name("TestEnum");
411 AddField(message, "baz", 500000000,
412 FieldDescriptorProto::LABEL_REPEATED,
413 FieldDescriptorProto::TYPE_MESSAGE)
414 ->set_type_name("TestForeign");
415 AddField(message, "qux", 15,
416 FieldDescriptorProto::LABEL_OPTIONAL,
417 FieldDescriptorProto::TYPE_GROUP)
418 ->set_type_name("TestForeign");
419
420 FileDescriptorProto bar_file;
421 bar_file.set_name("bar.proto");
422 bar_file.set_package("corge.grault");
423
424 DescriptorProto* message2 = AddMessage(&bar_file, "TestMessage2");
425 AddField(message2, "foo", 1,
426 FieldDescriptorProto::LABEL_REQUIRED,
427 FieldDescriptorProto::TYPE_STRING);
428 AddField(message2, "bar", 2,
429 FieldDescriptorProto::LABEL_REQUIRED,
430 FieldDescriptorProto::TYPE_STRING);
431 AddField(message2, "quux", 6,
432 FieldDescriptorProto::LABEL_REQUIRED,
433 FieldDescriptorProto::TYPE_STRING);
434
435 // Build the descriptors and get the pointers.
436 foo_file_ = pool_.BuildFile(foo_file);
437 ASSERT_TRUE(foo_file_ != NULL);
438
439 bar_file_ = pool_.BuildFile(bar_file);
440 ASSERT_TRUE(bar_file_ != NULL);
441
442 ASSERT_EQ(1, foo_file_->enum_type_count());
443 enum_ = foo_file_->enum_type(0);
444
445 ASSERT_EQ(2, foo_file_->message_type_count());
446 foreign_ = foo_file_->message_type(0);
447 message_ = foo_file_->message_type(1);
448
449 ASSERT_EQ(4, message_->field_count());
450 foo_ = message_->field(0);
451 bar_ = message_->field(1);
452 baz_ = message_->field(2);
453 qux_ = message_->field(3);
454
455 ASSERT_EQ(1, bar_file_->message_type_count());
456 message2_ = bar_file_->message_type(0);
457
458 ASSERT_EQ(3, message2_->field_count());
459 foo2_ = message2_->field(0);
460 bar2_ = message2_->field(1);
461 quux2_ = message2_->field(2);
462 }
463
464 DescriptorPool pool_;
465
466 const FileDescriptor* foo_file_;
467 const FileDescriptor* bar_file_;
468
469 const Descriptor* message_;
470 const Descriptor* message2_;
471 const Descriptor* foreign_;
472 const EnumDescriptor* enum_;
473
474 const FieldDescriptor* foo_;
475 const FieldDescriptor* bar_;
476 const FieldDescriptor* baz_;
477 const FieldDescriptor* qux_;
478
479 const FieldDescriptor* foo2_;
480 const FieldDescriptor* bar2_;
481 const FieldDescriptor* quux2_;
482};
483
484TEST_F(DescriptorTest, Name) {
485 EXPECT_EQ("TestMessage", message_->name());
486 EXPECT_EQ("TestMessage", message_->full_name());
487 EXPECT_EQ(foo_file_, message_->file());
488
489 EXPECT_EQ("TestMessage2", message2_->name());
490 EXPECT_EQ("corge.grault.TestMessage2", message2_->full_name());
491 EXPECT_EQ(bar_file_, message2_->file());
492}
493
494TEST_F(DescriptorTest, ContainingType) {
495 EXPECT_TRUE(message_->containing_type() == NULL);
496 EXPECT_TRUE(message2_->containing_type() == NULL);
497}
498
499TEST_F(DescriptorTest, FieldsByIndex) {
500 ASSERT_EQ(4, message_->field_count());
501 EXPECT_EQ(foo_, message_->field(0));
502 EXPECT_EQ(bar_, message_->field(1));
503 EXPECT_EQ(baz_, message_->field(2));
504 EXPECT_EQ(qux_, message_->field(3));
505}
506
507TEST_F(DescriptorTest, FindFieldByName) {
508 // All messages in the same DescriptorPool share a single lookup table for
509 // fields. So, in addition to testing that FindFieldByName finds the fields
510 // of the message, we need to test that it does *not* find the fields of
511 // *other* messages.
512
513 EXPECT_EQ(foo_, message_->FindFieldByName("foo"));
514 EXPECT_EQ(bar_, message_->FindFieldByName("bar"));
515 EXPECT_EQ(baz_, message_->FindFieldByName("baz"));
516 EXPECT_EQ(qux_, message_->FindFieldByName("qux"));
517 EXPECT_TRUE(message_->FindFieldByName("no_such_field") == NULL);
518 EXPECT_TRUE(message_->FindFieldByName("quux") == NULL);
519
520 EXPECT_EQ(foo2_ , message2_->FindFieldByName("foo" ));
521 EXPECT_EQ(bar2_ , message2_->FindFieldByName("bar" ));
522 EXPECT_EQ(quux2_, message2_->FindFieldByName("quux"));
523 EXPECT_TRUE(message2_->FindFieldByName("baz") == NULL);
524 EXPECT_TRUE(message2_->FindFieldByName("qux") == NULL);
525}
526
527TEST_F(DescriptorTest, FindFieldByNumber) {
528 EXPECT_EQ(foo_, message_->FindFieldByNumber(1));
529 EXPECT_EQ(bar_, message_->FindFieldByNumber(6));
530 EXPECT_EQ(baz_, message_->FindFieldByNumber(500000000));
531 EXPECT_EQ(qux_, message_->FindFieldByNumber(15));
532 EXPECT_TRUE(message_->FindFieldByNumber(837592) == NULL);
533 EXPECT_TRUE(message_->FindFieldByNumber(2) == NULL);
534
535 EXPECT_EQ(foo2_ , message2_->FindFieldByNumber(1));
536 EXPECT_EQ(bar2_ , message2_->FindFieldByNumber(2));
537 EXPECT_EQ(quux2_, message2_->FindFieldByNumber(6));
538 EXPECT_TRUE(message2_->FindFieldByNumber(15) == NULL);
539 EXPECT_TRUE(message2_->FindFieldByNumber(500000000) == NULL);
540}
541
542TEST_F(DescriptorTest, FieldName) {
543 EXPECT_EQ("foo", foo_->name());
544 EXPECT_EQ("bar", bar_->name());
545 EXPECT_EQ("baz", baz_->name());
546 EXPECT_EQ("qux", qux_->name());
547}
548
549TEST_F(DescriptorTest, FieldFullName) {
550 EXPECT_EQ("TestMessage.foo", foo_->full_name());
551 EXPECT_EQ("TestMessage.bar", bar_->full_name());
552 EXPECT_EQ("TestMessage.baz", baz_->full_name());
553 EXPECT_EQ("TestMessage.qux", qux_->full_name());
554
555 EXPECT_EQ("corge.grault.TestMessage2.foo", foo2_->full_name());
556 EXPECT_EQ("corge.grault.TestMessage2.bar", bar2_->full_name());
557 EXPECT_EQ("corge.grault.TestMessage2.quux", quux2_->full_name());
558}
559
560TEST_F(DescriptorTest, FieldFile) {
561 EXPECT_EQ(foo_file_, foo_->file());
562 EXPECT_EQ(foo_file_, bar_->file());
563 EXPECT_EQ(foo_file_, baz_->file());
564 EXPECT_EQ(foo_file_, qux_->file());
565
566 EXPECT_EQ(bar_file_, foo2_->file());
567 EXPECT_EQ(bar_file_, bar2_->file());
568 EXPECT_EQ(bar_file_, quux2_->file());
569}
570
571TEST_F(DescriptorTest, FieldIndex) {
572 EXPECT_EQ(0, foo_->index());
573 EXPECT_EQ(1, bar_->index());
574 EXPECT_EQ(2, baz_->index());
575 EXPECT_EQ(3, qux_->index());
576}
577
578TEST_F(DescriptorTest, FieldNumber) {
579 EXPECT_EQ( 1, foo_->number());
580 EXPECT_EQ( 6, bar_->number());
581 EXPECT_EQ(500000000, baz_->number());
582 EXPECT_EQ( 15, qux_->number());
583}
584
585TEST_F(DescriptorTest, FieldType) {
586 EXPECT_EQ(FieldDescriptor::TYPE_STRING , foo_->type());
587 EXPECT_EQ(FieldDescriptor::TYPE_ENUM , bar_->type());
588 EXPECT_EQ(FieldDescriptor::TYPE_MESSAGE, baz_->type());
589 EXPECT_EQ(FieldDescriptor::TYPE_GROUP , qux_->type());
590}
591
592TEST_F(DescriptorTest, FieldLabel) {
593 EXPECT_EQ(FieldDescriptor::LABEL_REQUIRED, foo_->label());
594 EXPECT_EQ(FieldDescriptor::LABEL_OPTIONAL, bar_->label());
595 EXPECT_EQ(FieldDescriptor::LABEL_REPEATED, baz_->label());
596 EXPECT_EQ(FieldDescriptor::LABEL_OPTIONAL, qux_->label());
597
598 EXPECT_TRUE (foo_->is_required());
599 EXPECT_FALSE(foo_->is_optional());
600 EXPECT_FALSE(foo_->is_repeated());
601
602 EXPECT_FALSE(bar_->is_required());
603 EXPECT_TRUE (bar_->is_optional());
604 EXPECT_FALSE(bar_->is_repeated());
605
606 EXPECT_FALSE(baz_->is_required());
607 EXPECT_FALSE(baz_->is_optional());
608 EXPECT_TRUE (baz_->is_repeated());
609}
610
611TEST_F(DescriptorTest, FieldHasDefault) {
612 EXPECT_FALSE(foo_->has_default_value());
613 EXPECT_FALSE(bar_->has_default_value());
614 EXPECT_FALSE(baz_->has_default_value());
615 EXPECT_FALSE(qux_->has_default_value());
616}
617
618TEST_F(DescriptorTest, FieldContainingType) {
619 EXPECT_EQ(message_, foo_->containing_type());
620 EXPECT_EQ(message_, bar_->containing_type());
621 EXPECT_EQ(message_, baz_->containing_type());
622 EXPECT_EQ(message_, qux_->containing_type());
623
624 EXPECT_EQ(message2_, foo2_ ->containing_type());
625 EXPECT_EQ(message2_, bar2_ ->containing_type());
626 EXPECT_EQ(message2_, quux2_->containing_type());
627}
628
629TEST_F(DescriptorTest, FieldMessageType) {
630 EXPECT_TRUE(foo_->message_type() == NULL);
631 EXPECT_TRUE(bar_->message_type() == NULL);
632
633 EXPECT_EQ(foreign_, baz_->message_type());
634 EXPECT_EQ(foreign_, qux_->message_type());
635}
636
637TEST_F(DescriptorTest, FieldEnumType) {
638 EXPECT_TRUE(foo_->enum_type() == NULL);
639 EXPECT_TRUE(baz_->enum_type() == NULL);
640 EXPECT_TRUE(qux_->enum_type() == NULL);
641
642 EXPECT_EQ(enum_, bar_->enum_type());
643}
644
645// ===================================================================
646
kenton@google.com2d6daa72009-01-22 01:27:00 +0000647class StylizedFieldNamesTest : public testing::Test {
648 protected:
649 void SetUp() {
650 FileDescriptorProto file;
651 file.set_name("foo.proto");
652
653 AddExtensionRange(AddMessage(&file, "ExtendableMessage"), 1, 1000);
654
655 DescriptorProto* message = AddMessage(&file, "TestMessage");
656 AddField(message, "foo_foo", 1,
657 FieldDescriptorProto::LABEL_OPTIONAL,
658 FieldDescriptorProto::TYPE_INT32);
659 AddField(message, "FooBar", 2,
660 FieldDescriptorProto::LABEL_OPTIONAL,
661 FieldDescriptorProto::TYPE_INT32);
662 AddField(message, "fooBaz", 3,
663 FieldDescriptorProto::LABEL_OPTIONAL,
664 FieldDescriptorProto::TYPE_INT32);
665 AddField(message, "fooFoo", 4, // Camel-case conflict with foo_foo.
666 FieldDescriptorProto::LABEL_OPTIONAL,
667 FieldDescriptorProto::TYPE_INT32);
668 AddField(message, "foobar", 5, // Lower-case conflict with FooBar.
669 FieldDescriptorProto::LABEL_OPTIONAL,
670 FieldDescriptorProto::TYPE_INT32);
671
672 AddNestedExtension(message, "ExtendableMessage", "bar_foo", 1,
673 FieldDescriptorProto::LABEL_OPTIONAL,
674 FieldDescriptorProto::TYPE_INT32);
675 AddNestedExtension(message, "ExtendableMessage", "BarBar", 2,
676 FieldDescriptorProto::LABEL_OPTIONAL,
677 FieldDescriptorProto::TYPE_INT32);
678 AddNestedExtension(message, "ExtendableMessage", "BarBaz", 3,
679 FieldDescriptorProto::LABEL_OPTIONAL,
680 FieldDescriptorProto::TYPE_INT32);
681 AddNestedExtension(message, "ExtendableMessage", "barFoo", 4, // Conflict
682 FieldDescriptorProto::LABEL_OPTIONAL,
683 FieldDescriptorProto::TYPE_INT32);
684 AddNestedExtension(message, "ExtendableMessage", "barbar", 5, // Conflict
685 FieldDescriptorProto::LABEL_OPTIONAL,
686 FieldDescriptorProto::TYPE_INT32);
687
688 AddExtension(&file, "ExtendableMessage", "baz_foo", 11,
689 FieldDescriptorProto::LABEL_OPTIONAL,
690 FieldDescriptorProto::TYPE_INT32);
691 AddExtension(&file, "ExtendableMessage", "BazBar", 12,
692 FieldDescriptorProto::LABEL_OPTIONAL,
693 FieldDescriptorProto::TYPE_INT32);
694 AddExtension(&file, "ExtendableMessage", "BazBaz", 13,
695 FieldDescriptorProto::LABEL_OPTIONAL,
696 FieldDescriptorProto::TYPE_INT32);
697 AddExtension(&file, "ExtendableMessage", "bazFoo", 14, // Conflict
698 FieldDescriptorProto::LABEL_OPTIONAL,
699 FieldDescriptorProto::TYPE_INT32);
700 AddExtension(&file, "ExtendableMessage", "bazbar", 15, // Conflict
701 FieldDescriptorProto::LABEL_OPTIONAL,
702 FieldDescriptorProto::TYPE_INT32);
703
704 file_ = pool_.BuildFile(file);
705 ASSERT_TRUE(file_ != NULL);
706 ASSERT_EQ(2, file_->message_type_count());
707 message_ = file_->message_type(1);
708 ASSERT_EQ("TestMessage", message_->name());
709 ASSERT_EQ(5, message_->field_count());
710 ASSERT_EQ(5, message_->extension_count());
711 ASSERT_EQ(5, file_->extension_count());
712 }
713
714 DescriptorPool pool_;
715 const FileDescriptor* file_;
716 const Descriptor* message_;
717};
718
719TEST_F(StylizedFieldNamesTest, LowercaseName) {
720 EXPECT_EQ("foo_foo", message_->field(0)->lowercase_name());
721 EXPECT_EQ("foobar" , message_->field(1)->lowercase_name());
722 EXPECT_EQ("foobaz" , message_->field(2)->lowercase_name());
723 EXPECT_EQ("foofoo" , message_->field(3)->lowercase_name());
724 EXPECT_EQ("foobar" , message_->field(4)->lowercase_name());
725
726 EXPECT_EQ("bar_foo", message_->extension(0)->lowercase_name());
727 EXPECT_EQ("barbar" , message_->extension(1)->lowercase_name());
728 EXPECT_EQ("barbaz" , message_->extension(2)->lowercase_name());
729 EXPECT_EQ("barfoo" , message_->extension(3)->lowercase_name());
730 EXPECT_EQ("barbar" , message_->extension(4)->lowercase_name());
731
732 EXPECT_EQ("baz_foo", file_->extension(0)->lowercase_name());
733 EXPECT_EQ("bazbar" , file_->extension(1)->lowercase_name());
734 EXPECT_EQ("bazbaz" , file_->extension(2)->lowercase_name());
735 EXPECT_EQ("bazfoo" , file_->extension(3)->lowercase_name());
736 EXPECT_EQ("bazbar" , file_->extension(4)->lowercase_name());
737}
738
739TEST_F(StylizedFieldNamesTest, CamelcaseName) {
740 EXPECT_EQ("fooFoo", message_->field(0)->camelcase_name());
741 EXPECT_EQ("fooBar", message_->field(1)->camelcase_name());
742 EXPECT_EQ("fooBaz", message_->field(2)->camelcase_name());
743 EXPECT_EQ("fooFoo", message_->field(3)->camelcase_name());
744 EXPECT_EQ("foobar", message_->field(4)->camelcase_name());
745
746 EXPECT_EQ("barFoo", message_->extension(0)->camelcase_name());
747 EXPECT_EQ("barBar", message_->extension(1)->camelcase_name());
748 EXPECT_EQ("barBaz", message_->extension(2)->camelcase_name());
749 EXPECT_EQ("barFoo", message_->extension(3)->camelcase_name());
750 EXPECT_EQ("barbar", message_->extension(4)->camelcase_name());
751
752 EXPECT_EQ("bazFoo", file_->extension(0)->camelcase_name());
753 EXPECT_EQ("bazBar", file_->extension(1)->camelcase_name());
754 EXPECT_EQ("bazBaz", file_->extension(2)->camelcase_name());
755 EXPECT_EQ("bazFoo", file_->extension(3)->camelcase_name());
756 EXPECT_EQ("bazbar", file_->extension(4)->camelcase_name());
757}
758
759TEST_F(StylizedFieldNamesTest, FindByLowercaseName) {
760 EXPECT_EQ(message_->field(0),
761 message_->FindFieldByLowercaseName("foo_foo"));
762 EXPECT_EQ(message_->field(1),
763 message_->FindFieldByLowercaseName("foobar"));
764 EXPECT_EQ(message_->field(2),
765 message_->FindFieldByLowercaseName("foobaz"));
766 EXPECT_TRUE(message_->FindFieldByLowercaseName("FooBar") == NULL);
767 EXPECT_TRUE(message_->FindFieldByLowercaseName("fooBaz") == NULL);
768 EXPECT_TRUE(message_->FindFieldByLowercaseName("bar_foo") == NULL);
769 EXPECT_TRUE(message_->FindFieldByLowercaseName("nosuchfield") == NULL);
770
771 EXPECT_EQ(message_->extension(0),
772 message_->FindExtensionByLowercaseName("bar_foo"));
773 EXPECT_EQ(message_->extension(1),
774 message_->FindExtensionByLowercaseName("barbar"));
775 EXPECT_EQ(message_->extension(2),
776 message_->FindExtensionByLowercaseName("barbaz"));
777 EXPECT_TRUE(message_->FindExtensionByLowercaseName("BarBar") == NULL);
778 EXPECT_TRUE(message_->FindExtensionByLowercaseName("barBaz") == NULL);
779 EXPECT_TRUE(message_->FindExtensionByLowercaseName("foo_foo") == NULL);
780 EXPECT_TRUE(message_->FindExtensionByLowercaseName("nosuchfield") == NULL);
781
782 EXPECT_EQ(file_->extension(0),
783 file_->FindExtensionByLowercaseName("baz_foo"));
784 EXPECT_EQ(file_->extension(1),
785 file_->FindExtensionByLowercaseName("bazbar"));
786 EXPECT_EQ(file_->extension(2),
787 file_->FindExtensionByLowercaseName("bazbaz"));
788 EXPECT_TRUE(file_->FindExtensionByLowercaseName("BazBar") == NULL);
789 EXPECT_TRUE(file_->FindExtensionByLowercaseName("bazBaz") == NULL);
790 EXPECT_TRUE(file_->FindExtensionByLowercaseName("nosuchfield") == NULL);
791}
792
793TEST_F(StylizedFieldNamesTest, FindByCamelcaseName) {
794 EXPECT_EQ(message_->field(0),
795 message_->FindFieldByCamelcaseName("fooFoo"));
796 EXPECT_EQ(message_->field(1),
797 message_->FindFieldByCamelcaseName("fooBar"));
798 EXPECT_EQ(message_->field(2),
799 message_->FindFieldByCamelcaseName("fooBaz"));
800 EXPECT_TRUE(message_->FindFieldByCamelcaseName("foo_foo") == NULL);
801 EXPECT_TRUE(message_->FindFieldByCamelcaseName("FooBar") == NULL);
802 EXPECT_TRUE(message_->FindFieldByCamelcaseName("barFoo") == NULL);
803 EXPECT_TRUE(message_->FindFieldByCamelcaseName("nosuchfield") == NULL);
804
805 EXPECT_EQ(message_->extension(0),
806 message_->FindExtensionByCamelcaseName("barFoo"));
807 EXPECT_EQ(message_->extension(1),
808 message_->FindExtensionByCamelcaseName("barBar"));
809 EXPECT_EQ(message_->extension(2),
810 message_->FindExtensionByCamelcaseName("barBaz"));
811 EXPECT_TRUE(message_->FindExtensionByCamelcaseName("bar_foo") == NULL);
812 EXPECT_TRUE(message_->FindExtensionByCamelcaseName("BarBar") == NULL);
813 EXPECT_TRUE(message_->FindExtensionByCamelcaseName("fooFoo") == NULL);
814 EXPECT_TRUE(message_->FindExtensionByCamelcaseName("nosuchfield") == NULL);
815
816 EXPECT_EQ(file_->extension(0),
817 file_->FindExtensionByCamelcaseName("bazFoo"));
818 EXPECT_EQ(file_->extension(1),
819 file_->FindExtensionByCamelcaseName("bazBar"));
820 EXPECT_EQ(file_->extension(2),
821 file_->FindExtensionByCamelcaseName("bazBaz"));
822 EXPECT_TRUE(file_->FindExtensionByCamelcaseName("baz_foo") == NULL);
823 EXPECT_TRUE(file_->FindExtensionByCamelcaseName("BazBar") == NULL);
824 EXPECT_TRUE(file_->FindExtensionByCamelcaseName("nosuchfield") == NULL);
825}
826
827// ===================================================================
828
temporal40ee5512008-07-10 02:12:20 +0000829// Test enum descriptors.
830class EnumDescriptorTest : public testing::Test {
831 protected:
832 virtual void SetUp() {
833 // Build descriptors for the following definitions:
834 //
835 // // in "foo.proto"
836 // enum TestEnum {
837 // FOO = 1;
838 // BAR = 2;
839 // }
840 //
841 // // in "bar.proto"
842 // package corge.grault;
843 // enum TestEnum2 {
844 // FOO = 1;
845 // BAZ = 3;
846 // }
847 //
848 // TestEnum2 is primarily here to test FindValueByName and friends.
849 // All enums created from the same DescriptorPool share the same lookup
850 // table, so we need to insure that they don't interfere.
851
852 // TestEnum
853 FileDescriptorProto foo_file;
854 foo_file.set_name("foo.proto");
855
856 EnumDescriptorProto* enum_proto = AddEnum(&foo_file, "TestEnum");
857 AddEnumValue(enum_proto, "FOO", 1);
858 AddEnumValue(enum_proto, "BAR", 2);
859
860 // TestEnum2
861 FileDescriptorProto bar_file;
862 bar_file.set_name("bar.proto");
863 bar_file.set_package("corge.grault");
864
865 EnumDescriptorProto* enum2_proto = AddEnum(&bar_file, "TestEnum2");
866 AddEnumValue(enum2_proto, "FOO", 1);
867 AddEnumValue(enum2_proto, "BAZ", 3);
868
869 // Build the descriptors and get the pointers.
870 foo_file_ = pool_.BuildFile(foo_file);
871 ASSERT_TRUE(foo_file_ != NULL);
872
873 bar_file_ = pool_.BuildFile(bar_file);
874 ASSERT_TRUE(bar_file_ != NULL);
875
876 ASSERT_EQ(1, foo_file_->enum_type_count());
877 enum_ = foo_file_->enum_type(0);
878
879 ASSERT_EQ(2, enum_->value_count());
880 foo_ = enum_->value(0);
881 bar_ = enum_->value(1);
882
883 ASSERT_EQ(1, bar_file_->enum_type_count());
884 enum2_ = bar_file_->enum_type(0);
885
886 ASSERT_EQ(2, enum2_->value_count());
887 foo2_ = enum2_->value(0);
888 baz2_ = enum2_->value(1);
889 }
890
891 DescriptorPool pool_;
892
893 const FileDescriptor* foo_file_;
894 const FileDescriptor* bar_file_;
895
896 const EnumDescriptor* enum_;
897 const EnumDescriptor* enum2_;
898
899 const EnumValueDescriptor* foo_;
900 const EnumValueDescriptor* bar_;
901
902 const EnumValueDescriptor* foo2_;
903 const EnumValueDescriptor* baz2_;
904};
905
906TEST_F(EnumDescriptorTest, Name) {
907 EXPECT_EQ("TestEnum", enum_->name());
908 EXPECT_EQ("TestEnum", enum_->full_name());
909 EXPECT_EQ(foo_file_, enum_->file());
910
911 EXPECT_EQ("TestEnum2", enum2_->name());
912 EXPECT_EQ("corge.grault.TestEnum2", enum2_->full_name());
913 EXPECT_EQ(bar_file_, enum2_->file());
914}
915
916TEST_F(EnumDescriptorTest, ContainingType) {
917 EXPECT_TRUE(enum_->containing_type() == NULL);
918 EXPECT_TRUE(enum2_->containing_type() == NULL);
919}
920
921TEST_F(EnumDescriptorTest, ValuesByIndex) {
922 ASSERT_EQ(2, enum_->value_count());
923 EXPECT_EQ(foo_, enum_->value(0));
924 EXPECT_EQ(bar_, enum_->value(1));
925}
926
927TEST_F(EnumDescriptorTest, FindValueByName) {
928 EXPECT_EQ(foo_ , enum_ ->FindValueByName("FOO"));
929 EXPECT_EQ(bar_ , enum_ ->FindValueByName("BAR"));
930 EXPECT_EQ(foo2_, enum2_->FindValueByName("FOO"));
931 EXPECT_EQ(baz2_, enum2_->FindValueByName("BAZ"));
932
933 EXPECT_TRUE(enum_ ->FindValueByName("NO_SUCH_VALUE") == NULL);
934 EXPECT_TRUE(enum_ ->FindValueByName("BAZ" ) == NULL);
935 EXPECT_TRUE(enum2_->FindValueByName("BAR" ) == NULL);
936}
937
938TEST_F(EnumDescriptorTest, FindValueByNumber) {
939 EXPECT_EQ(foo_ , enum_ ->FindValueByNumber(1));
940 EXPECT_EQ(bar_ , enum_ ->FindValueByNumber(2));
941 EXPECT_EQ(foo2_, enum2_->FindValueByNumber(1));
942 EXPECT_EQ(baz2_, enum2_->FindValueByNumber(3));
943
944 EXPECT_TRUE(enum_ ->FindValueByNumber(416) == NULL);
945 EXPECT_TRUE(enum_ ->FindValueByNumber(3) == NULL);
946 EXPECT_TRUE(enum2_->FindValueByNumber(2) == NULL);
947}
948
949TEST_F(EnumDescriptorTest, ValueName) {
950 EXPECT_EQ("FOO", foo_->name());
951 EXPECT_EQ("BAR", bar_->name());
952}
953
954TEST_F(EnumDescriptorTest, ValueFullName) {
955 EXPECT_EQ("FOO", foo_->full_name());
956 EXPECT_EQ("BAR", bar_->full_name());
957 EXPECT_EQ("corge.grault.FOO", foo2_->full_name());
958 EXPECT_EQ("corge.grault.BAZ", baz2_->full_name());
959}
960
961TEST_F(EnumDescriptorTest, ValueIndex) {
962 EXPECT_EQ(0, foo_->index());
963 EXPECT_EQ(1, bar_->index());
964}
965
966TEST_F(EnumDescriptorTest, ValueNumber) {
967 EXPECT_EQ(1, foo_->number());
968 EXPECT_EQ(2, bar_->number());
969}
970
971TEST_F(EnumDescriptorTest, ValueType) {
972 EXPECT_EQ(enum_ , foo_ ->type());
973 EXPECT_EQ(enum_ , bar_ ->type());
974 EXPECT_EQ(enum2_, foo2_->type());
975 EXPECT_EQ(enum2_, baz2_->type());
976}
977
978// ===================================================================
979
980// Test service descriptors.
981class ServiceDescriptorTest : public testing::Test {
982 protected:
983 virtual void SetUp() {
984 // Build descriptors for the following messages and service:
985 // // in "foo.proto"
986 // message FooRequest {}
987 // message FooResponse {}
988 // message BarRequest {}
989 // message BarResponse {}
990 // message BazRequest {}
991 // message BazResponse {}
992 //
993 // service TestService {
994 // rpc Foo(FooRequest) returns (FooResponse);
995 // rpc Bar(BarRequest) returns (BarResponse);
996 // }
997 //
998 // // in "bar.proto"
999 // package corge.grault
1000 // service TestService2 {
1001 // rpc Foo(FooRequest) returns (FooResponse);
1002 // rpc Baz(BazRequest) returns (BazResponse);
1003 // }
1004
1005 FileDescriptorProto foo_file;
1006 foo_file.set_name("foo.proto");
1007
1008 AddMessage(&foo_file, "FooRequest");
1009 AddMessage(&foo_file, "FooResponse");
1010 AddMessage(&foo_file, "BarRequest");
1011 AddMessage(&foo_file, "BarResponse");
1012 AddMessage(&foo_file, "BazRequest");
1013 AddMessage(&foo_file, "BazResponse");
1014
1015 ServiceDescriptorProto* service = AddService(&foo_file, "TestService");
1016 AddMethod(service, "Foo", "FooRequest", "FooResponse");
1017 AddMethod(service, "Bar", "BarRequest", "BarResponse");
1018
1019 FileDescriptorProto bar_file;
1020 bar_file.set_name("bar.proto");
1021 bar_file.set_package("corge.grault");
1022 bar_file.add_dependency("foo.proto");
1023
1024 ServiceDescriptorProto* service2 = AddService(&bar_file, "TestService2");
1025 AddMethod(service2, "Foo", "FooRequest", "FooResponse");
1026 AddMethod(service2, "Baz", "BazRequest", "BazResponse");
1027
1028 // Build the descriptors and get the pointers.
1029 foo_file_ = pool_.BuildFile(foo_file);
1030 ASSERT_TRUE(foo_file_ != NULL);
1031
1032 bar_file_ = pool_.BuildFile(bar_file);
1033 ASSERT_TRUE(bar_file_ != NULL);
1034
1035 ASSERT_EQ(6, foo_file_->message_type_count());
1036 foo_request_ = foo_file_->message_type(0);
1037 foo_response_ = foo_file_->message_type(1);
1038 bar_request_ = foo_file_->message_type(2);
1039 bar_response_ = foo_file_->message_type(3);
1040 baz_request_ = foo_file_->message_type(4);
1041 baz_response_ = foo_file_->message_type(5);
1042
1043 ASSERT_EQ(1, foo_file_->service_count());
1044 service_ = foo_file_->service(0);
1045
1046 ASSERT_EQ(2, service_->method_count());
1047 foo_ = service_->method(0);
1048 bar_ = service_->method(1);
1049
1050 ASSERT_EQ(1, bar_file_->service_count());
1051 service2_ = bar_file_->service(0);
1052
1053 ASSERT_EQ(2, service2_->method_count());
1054 foo2_ = service2_->method(0);
1055 baz2_ = service2_->method(1);
1056 }
1057
1058 DescriptorPool pool_;
1059
1060 const FileDescriptor* foo_file_;
1061 const FileDescriptor* bar_file_;
1062
1063 const Descriptor* foo_request_;
1064 const Descriptor* foo_response_;
1065 const Descriptor* bar_request_;
1066 const Descriptor* bar_response_;
1067 const Descriptor* baz_request_;
1068 const Descriptor* baz_response_;
1069
1070 const ServiceDescriptor* service_;
1071 const ServiceDescriptor* service2_;
1072
1073 const MethodDescriptor* foo_;
1074 const MethodDescriptor* bar_;
1075
1076 const MethodDescriptor* foo2_;
1077 const MethodDescriptor* baz2_;
1078};
1079
1080TEST_F(ServiceDescriptorTest, Name) {
1081 EXPECT_EQ("TestService", service_->name());
1082 EXPECT_EQ("TestService", service_->full_name());
1083 EXPECT_EQ(foo_file_, service_->file());
1084
1085 EXPECT_EQ("TestService2", service2_->name());
1086 EXPECT_EQ("corge.grault.TestService2", service2_->full_name());
1087 EXPECT_EQ(bar_file_, service2_->file());
1088}
1089
1090TEST_F(ServiceDescriptorTest, MethodsByIndex) {
1091 ASSERT_EQ(2, service_->method_count());
1092 EXPECT_EQ(foo_, service_->method(0));
1093 EXPECT_EQ(bar_, service_->method(1));
1094}
1095
1096TEST_F(ServiceDescriptorTest, FindMethodByName) {
1097 EXPECT_EQ(foo_ , service_ ->FindMethodByName("Foo"));
1098 EXPECT_EQ(bar_ , service_ ->FindMethodByName("Bar"));
1099 EXPECT_EQ(foo2_, service2_->FindMethodByName("Foo"));
1100 EXPECT_EQ(baz2_, service2_->FindMethodByName("Baz"));
1101
1102 EXPECT_TRUE(service_ ->FindMethodByName("NoSuchMethod") == NULL);
1103 EXPECT_TRUE(service_ ->FindMethodByName("Baz" ) == NULL);
1104 EXPECT_TRUE(service2_->FindMethodByName("Bar" ) == NULL);
1105}
1106
1107TEST_F(ServiceDescriptorTest, MethodName) {
1108 EXPECT_EQ("Foo", foo_->name());
1109 EXPECT_EQ("Bar", bar_->name());
1110}
1111
1112TEST_F(ServiceDescriptorTest, MethodFullName) {
1113 EXPECT_EQ("TestService.Foo", foo_->full_name());
1114 EXPECT_EQ("TestService.Bar", bar_->full_name());
1115 EXPECT_EQ("corge.grault.TestService2.Foo", foo2_->full_name());
1116 EXPECT_EQ("corge.grault.TestService2.Baz", baz2_->full_name());
1117}
1118
1119TEST_F(ServiceDescriptorTest, MethodIndex) {
1120 EXPECT_EQ(0, foo_->index());
1121 EXPECT_EQ(1, bar_->index());
1122}
1123
1124TEST_F(ServiceDescriptorTest, MethodParent) {
1125 EXPECT_EQ(service_, foo_->service());
1126 EXPECT_EQ(service_, bar_->service());
1127}
1128
1129TEST_F(ServiceDescriptorTest, MethodInputType) {
1130 EXPECT_EQ(foo_request_, foo_->input_type());
1131 EXPECT_EQ(bar_request_, bar_->input_type());
1132}
1133
1134TEST_F(ServiceDescriptorTest, MethodOutputType) {
1135 EXPECT_EQ(foo_response_, foo_->output_type());
1136 EXPECT_EQ(bar_response_, bar_->output_type());
1137}
1138
1139// ===================================================================
1140
1141// Test nested types.
1142class NestedDescriptorTest : public testing::Test {
1143 protected:
1144 virtual void SetUp() {
1145 // Build descriptors for the following definitions:
1146 //
1147 // // in "foo.proto"
1148 // message TestMessage {
1149 // message Foo {}
1150 // message Bar {}
1151 // enum Baz { A = 1; }
1152 // enum Qux { B = 1; }
1153 // }
1154 //
1155 // // in "bar.proto"
1156 // package corge.grault;
1157 // message TestMessage2 {
1158 // message Foo {}
1159 // message Baz {}
1160 // enum Qux { A = 1; }
1161 // enum Quux { C = 1; }
1162 // }
1163 //
1164 // TestMessage2 is primarily here to test FindNestedTypeByName and friends.
1165 // All messages created from the same DescriptorPool share the same lookup
1166 // table, so we need to insure that they don't interfere.
1167 //
1168 // We add enum values to the enums in order to test searching for enum
1169 // values across a message's scope.
1170
1171 FileDescriptorProto foo_file;
1172 foo_file.set_name("foo.proto");
1173
1174 DescriptorProto* message = AddMessage(&foo_file, "TestMessage");
1175 AddNestedMessage(message, "Foo");
1176 AddNestedMessage(message, "Bar");
1177 EnumDescriptorProto* baz = AddNestedEnum(message, "Baz");
1178 AddEnumValue(baz, "A", 1);
1179 EnumDescriptorProto* qux = AddNestedEnum(message, "Qux");
1180 AddEnumValue(qux, "B", 1);
1181
1182 FileDescriptorProto bar_file;
1183 bar_file.set_name("bar.proto");
1184 bar_file.set_package("corge.grault");
1185
1186 DescriptorProto* message2 = AddMessage(&bar_file, "TestMessage2");
1187 AddNestedMessage(message2, "Foo");
1188 AddNestedMessage(message2, "Baz");
1189 EnumDescriptorProto* qux2 = AddNestedEnum(message2, "Qux");
1190 AddEnumValue(qux2, "A", 1);
1191 EnumDescriptorProto* quux2 = AddNestedEnum(message2, "Quux");
1192 AddEnumValue(quux2, "C", 1);
1193
1194 // Build the descriptors and get the pointers.
1195 foo_file_ = pool_.BuildFile(foo_file);
1196 ASSERT_TRUE(foo_file_ != NULL);
1197
1198 bar_file_ = pool_.BuildFile(bar_file);
1199 ASSERT_TRUE(bar_file_ != NULL);
1200
1201 ASSERT_EQ(1, foo_file_->message_type_count());
1202 message_ = foo_file_->message_type(0);
1203
1204 ASSERT_EQ(2, message_->nested_type_count());
1205 foo_ = message_->nested_type(0);
1206 bar_ = message_->nested_type(1);
1207
1208 ASSERT_EQ(2, message_->enum_type_count());
1209 baz_ = message_->enum_type(0);
1210 qux_ = message_->enum_type(1);
1211
1212 ASSERT_EQ(1, baz_->value_count());
1213 a_ = baz_->value(0);
1214 ASSERT_EQ(1, qux_->value_count());
1215 b_ = qux_->value(0);
1216
1217 ASSERT_EQ(1, bar_file_->message_type_count());
1218 message2_ = bar_file_->message_type(0);
1219
1220 ASSERT_EQ(2, message2_->nested_type_count());
1221 foo2_ = message2_->nested_type(0);
1222 baz2_ = message2_->nested_type(1);
1223
1224 ASSERT_EQ(2, message2_->enum_type_count());
1225 qux2_ = message2_->enum_type(0);
1226 quux2_ = message2_->enum_type(1);
1227
1228 ASSERT_EQ(1, qux2_->value_count());
1229 a2_ = qux2_->value(0);
1230 ASSERT_EQ(1, quux2_->value_count());
1231 c2_ = quux2_->value(0);
1232 }
1233
1234 DescriptorPool pool_;
1235
1236 const FileDescriptor* foo_file_;
1237 const FileDescriptor* bar_file_;
1238
1239 const Descriptor* message_;
1240 const Descriptor* message2_;
1241
1242 const Descriptor* foo_;
1243 const Descriptor* bar_;
1244 const EnumDescriptor* baz_;
1245 const EnumDescriptor* qux_;
1246 const EnumValueDescriptor* a_;
1247 const EnumValueDescriptor* b_;
1248
1249 const Descriptor* foo2_;
1250 const Descriptor* baz2_;
1251 const EnumDescriptor* qux2_;
1252 const EnumDescriptor* quux2_;
1253 const EnumValueDescriptor* a2_;
1254 const EnumValueDescriptor* c2_;
1255};
1256
1257TEST_F(NestedDescriptorTest, MessageName) {
1258 EXPECT_EQ("Foo", foo_ ->name());
1259 EXPECT_EQ("Bar", bar_ ->name());
1260 EXPECT_EQ("Foo", foo2_->name());
1261 EXPECT_EQ("Baz", baz2_->name());
1262
1263 EXPECT_EQ("TestMessage.Foo", foo_->full_name());
1264 EXPECT_EQ("TestMessage.Bar", bar_->full_name());
1265 EXPECT_EQ("corge.grault.TestMessage2.Foo", foo2_->full_name());
1266 EXPECT_EQ("corge.grault.TestMessage2.Baz", baz2_->full_name());
1267}
1268
1269TEST_F(NestedDescriptorTest, MessageContainingType) {
1270 EXPECT_EQ(message_ , foo_ ->containing_type());
1271 EXPECT_EQ(message_ , bar_ ->containing_type());
1272 EXPECT_EQ(message2_, foo2_->containing_type());
1273 EXPECT_EQ(message2_, baz2_->containing_type());
1274}
1275
1276TEST_F(NestedDescriptorTest, NestedMessagesByIndex) {
1277 ASSERT_EQ(2, message_->nested_type_count());
1278 EXPECT_EQ(foo_, message_->nested_type(0));
1279 EXPECT_EQ(bar_, message_->nested_type(1));
1280}
1281
1282TEST_F(NestedDescriptorTest, FindFieldByNameDoesntFindNestedTypes) {
1283 EXPECT_TRUE(message_->FindFieldByName("Foo") == NULL);
1284 EXPECT_TRUE(message_->FindFieldByName("Qux") == NULL);
1285 EXPECT_TRUE(message_->FindExtensionByName("Foo") == NULL);
1286 EXPECT_TRUE(message_->FindExtensionByName("Qux") == NULL);
1287}
1288
1289TEST_F(NestedDescriptorTest, FindNestedTypeByName) {
1290 EXPECT_EQ(foo_ , message_ ->FindNestedTypeByName("Foo"));
1291 EXPECT_EQ(bar_ , message_ ->FindNestedTypeByName("Bar"));
1292 EXPECT_EQ(foo2_, message2_->FindNestedTypeByName("Foo"));
1293 EXPECT_EQ(baz2_, message2_->FindNestedTypeByName("Baz"));
1294
1295 EXPECT_TRUE(message_ ->FindNestedTypeByName("NoSuchType") == NULL);
1296 EXPECT_TRUE(message_ ->FindNestedTypeByName("Baz" ) == NULL);
1297 EXPECT_TRUE(message2_->FindNestedTypeByName("Bar" ) == NULL);
1298
1299 EXPECT_TRUE(message_->FindNestedTypeByName("Qux") == NULL);
1300}
1301
1302TEST_F(NestedDescriptorTest, EnumName) {
1303 EXPECT_EQ("Baz" , baz_ ->name());
1304 EXPECT_EQ("Qux" , qux_ ->name());
1305 EXPECT_EQ("Qux" , qux2_->name());
1306 EXPECT_EQ("Quux", quux2_->name());
1307
1308 EXPECT_EQ("TestMessage.Baz", baz_->full_name());
1309 EXPECT_EQ("TestMessage.Qux", qux_->full_name());
1310 EXPECT_EQ("corge.grault.TestMessage2.Qux" , qux2_ ->full_name());
1311 EXPECT_EQ("corge.grault.TestMessage2.Quux", quux2_->full_name());
1312}
1313
1314TEST_F(NestedDescriptorTest, EnumContainingType) {
1315 EXPECT_EQ(message_ , baz_ ->containing_type());
1316 EXPECT_EQ(message_ , qux_ ->containing_type());
1317 EXPECT_EQ(message2_, qux2_ ->containing_type());
1318 EXPECT_EQ(message2_, quux2_->containing_type());
1319}
1320
1321TEST_F(NestedDescriptorTest, NestedEnumsByIndex) {
1322 ASSERT_EQ(2, message_->nested_type_count());
1323 EXPECT_EQ(foo_, message_->nested_type(0));
1324 EXPECT_EQ(bar_, message_->nested_type(1));
1325}
1326
1327TEST_F(NestedDescriptorTest, FindEnumTypeByName) {
1328 EXPECT_EQ(baz_ , message_ ->FindEnumTypeByName("Baz" ));
1329 EXPECT_EQ(qux_ , message_ ->FindEnumTypeByName("Qux" ));
1330 EXPECT_EQ(qux2_ , message2_->FindEnumTypeByName("Qux" ));
1331 EXPECT_EQ(quux2_, message2_->FindEnumTypeByName("Quux"));
1332
1333 EXPECT_TRUE(message_ ->FindEnumTypeByName("NoSuchType") == NULL);
1334 EXPECT_TRUE(message_ ->FindEnumTypeByName("Quux" ) == NULL);
1335 EXPECT_TRUE(message2_->FindEnumTypeByName("Baz" ) == NULL);
1336
1337 EXPECT_TRUE(message_->FindEnumTypeByName("Foo") == NULL);
1338}
1339
1340TEST_F(NestedDescriptorTest, FindEnumValueByName) {
1341 EXPECT_EQ(a_ , message_ ->FindEnumValueByName("A"));
1342 EXPECT_EQ(b_ , message_ ->FindEnumValueByName("B"));
1343 EXPECT_EQ(a2_, message2_->FindEnumValueByName("A"));
1344 EXPECT_EQ(c2_, message2_->FindEnumValueByName("C"));
1345
1346 EXPECT_TRUE(message_ ->FindEnumValueByName("NO_SUCH_VALUE") == NULL);
1347 EXPECT_TRUE(message_ ->FindEnumValueByName("C" ) == NULL);
1348 EXPECT_TRUE(message2_->FindEnumValueByName("B" ) == NULL);
1349
1350 EXPECT_TRUE(message_->FindEnumValueByName("Foo") == NULL);
1351}
1352
1353// ===================================================================
1354
1355// Test extensions.
1356class ExtensionDescriptorTest : public testing::Test {
1357 protected:
1358 virtual void SetUp() {
1359 // Build descriptors for the following definitions:
1360 //
1361 // enum Baz {}
1362 // message Qux {}
1363 //
1364 // message Foo {
1365 // extensions 10 to 19;
1366 // extensions 30 to 39;
1367 // }
1368 // extends Foo with optional int32 foo_int32 = 10;
1369 // extends Foo with repeated TestEnum foo_enum = 19;
1370 // message Bar {
1371 // extends Foo with optional Qux foo_message = 30;
1372 // // (using Qux as the group type)
1373 // extends Foo with repeated group foo_group = 39;
1374 // }
1375
1376 FileDescriptorProto foo_file;
1377 foo_file.set_name("foo.proto");
1378
1379 AddEmptyEnum(&foo_file, "Baz");
1380 AddMessage(&foo_file, "Qux");
1381
1382 DescriptorProto* foo = AddMessage(&foo_file, "Foo");
1383 AddExtensionRange(foo, 10, 20);
1384 AddExtensionRange(foo, 30, 40);
1385
1386 AddExtension(&foo_file, "Foo", "foo_int32", 10,
1387 FieldDescriptorProto::LABEL_OPTIONAL,
1388 FieldDescriptorProto::TYPE_INT32);
1389 AddExtension(&foo_file, "Foo", "foo_enum", 19,
1390 FieldDescriptorProto::LABEL_REPEATED,
1391 FieldDescriptorProto::TYPE_ENUM)
1392 ->set_type_name("Baz");
1393
1394 DescriptorProto* bar = AddMessage(&foo_file, "Bar");
1395 AddNestedExtension(bar, "Foo", "foo_message", 30,
1396 FieldDescriptorProto::LABEL_OPTIONAL,
1397 FieldDescriptorProto::TYPE_MESSAGE)
1398 ->set_type_name("Qux");
1399 AddNestedExtension(bar, "Foo", "foo_group", 39,
1400 FieldDescriptorProto::LABEL_REPEATED,
1401 FieldDescriptorProto::TYPE_GROUP)
1402 ->set_type_name("Qux");
1403
1404 // Build the descriptors and get the pointers.
1405 foo_file_ = pool_.BuildFile(foo_file);
1406 ASSERT_TRUE(foo_file_ != NULL);
1407
1408 ASSERT_EQ(1, foo_file_->enum_type_count());
1409 baz_ = foo_file_->enum_type(0);
1410
1411 ASSERT_EQ(3, foo_file_->message_type_count());
1412 qux_ = foo_file_->message_type(0);
1413 foo_ = foo_file_->message_type(1);
1414 bar_ = foo_file_->message_type(2);
1415 }
1416
1417 DescriptorPool pool_;
1418
1419 const FileDescriptor* foo_file_;
1420
1421 const Descriptor* foo_;
1422 const Descriptor* bar_;
1423 const EnumDescriptor* baz_;
1424 const Descriptor* qux_;
1425};
1426
1427TEST_F(ExtensionDescriptorTest, ExtensionRanges) {
1428 EXPECT_EQ(0, bar_->extension_range_count());
1429 ASSERT_EQ(2, foo_->extension_range_count());
1430
1431 EXPECT_EQ(10, foo_->extension_range(0)->start);
1432 EXPECT_EQ(30, foo_->extension_range(1)->start);
1433
1434 EXPECT_EQ(20, foo_->extension_range(0)->end);
1435 EXPECT_EQ(40, foo_->extension_range(1)->end);
1436};
1437
1438TEST_F(ExtensionDescriptorTest, Extensions) {
1439 EXPECT_EQ(0, foo_->extension_count());
1440 ASSERT_EQ(2, foo_file_->extension_count());
1441 ASSERT_EQ(2, bar_->extension_count());
1442
1443 EXPECT_TRUE(foo_file_->extension(0)->is_extension());
1444 EXPECT_TRUE(foo_file_->extension(1)->is_extension());
1445 EXPECT_TRUE(bar_->extension(0)->is_extension());
1446 EXPECT_TRUE(bar_->extension(1)->is_extension());
1447
1448 EXPECT_EQ("foo_int32" , foo_file_->extension(0)->name());
1449 EXPECT_EQ("foo_enum" , foo_file_->extension(1)->name());
1450 EXPECT_EQ("foo_message", bar_->extension(0)->name());
1451 EXPECT_EQ("foo_group" , bar_->extension(1)->name());
1452
1453 EXPECT_EQ(10, foo_file_->extension(0)->number());
1454 EXPECT_EQ(19, foo_file_->extension(1)->number());
1455 EXPECT_EQ(30, bar_->extension(0)->number());
1456 EXPECT_EQ(39, bar_->extension(1)->number());
1457
1458 EXPECT_EQ(FieldDescriptor::TYPE_INT32 , foo_file_->extension(0)->type());
1459 EXPECT_EQ(FieldDescriptor::TYPE_ENUM , foo_file_->extension(1)->type());
1460 EXPECT_EQ(FieldDescriptor::TYPE_MESSAGE, bar_->extension(0)->type());
1461 EXPECT_EQ(FieldDescriptor::TYPE_GROUP , bar_->extension(1)->type());
1462
1463 EXPECT_EQ(baz_, foo_file_->extension(1)->enum_type());
1464 EXPECT_EQ(qux_, bar_->extension(0)->message_type());
1465 EXPECT_EQ(qux_, bar_->extension(1)->message_type());
1466
1467 EXPECT_EQ(FieldDescriptor::LABEL_OPTIONAL, foo_file_->extension(0)->label());
1468 EXPECT_EQ(FieldDescriptor::LABEL_REPEATED, foo_file_->extension(1)->label());
1469 EXPECT_EQ(FieldDescriptor::LABEL_OPTIONAL, bar_->extension(0)->label());
1470 EXPECT_EQ(FieldDescriptor::LABEL_REPEATED, bar_->extension(1)->label());
1471
1472 EXPECT_EQ(foo_, foo_file_->extension(0)->containing_type());
1473 EXPECT_EQ(foo_, foo_file_->extension(1)->containing_type());
1474 EXPECT_EQ(foo_, bar_->extension(0)->containing_type());
1475 EXPECT_EQ(foo_, bar_->extension(1)->containing_type());
1476
1477 EXPECT_TRUE(foo_file_->extension(0)->extension_scope() == NULL);
1478 EXPECT_TRUE(foo_file_->extension(1)->extension_scope() == NULL);
1479 EXPECT_EQ(bar_, bar_->extension(0)->extension_scope());
1480 EXPECT_EQ(bar_, bar_->extension(1)->extension_scope());
1481};
1482
1483TEST_F(ExtensionDescriptorTest, IsExtensionNumber) {
1484 EXPECT_FALSE(foo_->IsExtensionNumber( 9));
1485 EXPECT_TRUE (foo_->IsExtensionNumber(10));
1486 EXPECT_TRUE (foo_->IsExtensionNumber(19));
1487 EXPECT_FALSE(foo_->IsExtensionNumber(20));
1488 EXPECT_FALSE(foo_->IsExtensionNumber(29));
1489 EXPECT_TRUE (foo_->IsExtensionNumber(30));
1490 EXPECT_TRUE (foo_->IsExtensionNumber(39));
1491 EXPECT_FALSE(foo_->IsExtensionNumber(40));
1492}
1493
1494TEST_F(ExtensionDescriptorTest, FindExtensionByName) {
1495 // Note that FileDescriptor::FindExtensionByName() is tested by
1496 // FileDescriptorTest.
1497 ASSERT_EQ(2, bar_->extension_count());
1498
1499 EXPECT_EQ(bar_->extension(0), bar_->FindExtensionByName("foo_message"));
1500 EXPECT_EQ(bar_->extension(1), bar_->FindExtensionByName("foo_group" ));
1501
1502 EXPECT_TRUE(bar_->FindExtensionByName("no_such_extension") == NULL);
1503 EXPECT_TRUE(foo_->FindExtensionByName("foo_int32") == NULL);
1504 EXPECT_TRUE(foo_->FindExtensionByName("foo_message") == NULL);
1505}
1506
kenton@google.comd37d46d2009-04-25 02:53:47 +00001507TEST_F(ExtensionDescriptorTest, FindAllExtensions) {
1508 vector<const FieldDescriptor*> extensions;
1509 pool_.FindAllExtensions(foo_, &extensions);
1510 ASSERT_EQ(4, extensions.size());
1511 EXPECT_EQ(10, extensions[0]->number());
1512 EXPECT_EQ(19, extensions[1]->number());
1513 EXPECT_EQ(30, extensions[2]->number());
1514 EXPECT_EQ(39, extensions[3]->number());
1515}
1516
temporal40ee5512008-07-10 02:12:20 +00001517// ===================================================================
1518
1519class MiscTest : public testing::Test {
1520 protected:
1521 // Function which makes a field of the given type just to find out what its
1522 // cpp_type is.
1523 FieldDescriptor::CppType GetCppTypeForFieldType(FieldDescriptor::Type type) {
1524 FileDescriptorProto file_proto;
1525 file_proto.set_name("foo.proto");
1526 AddEmptyEnum(&file_proto, "DummyEnum");
1527
1528 DescriptorProto* message = AddMessage(&file_proto, "TestMessage");
1529 FieldDescriptorProto* field =
1530 AddField(message, "foo", 1, FieldDescriptorProto::LABEL_OPTIONAL,
kenton@google.coma2a32c22008-11-14 17:29:32 +00001531 static_cast<FieldDescriptorProto::Type>(static_cast<int>(type)));
temporal40ee5512008-07-10 02:12:20 +00001532
1533 if (type == FieldDescriptor::TYPE_MESSAGE ||
1534 type == FieldDescriptor::TYPE_GROUP) {
1535 field->set_type_name("TestMessage");
1536 } else if (type == FieldDescriptor::TYPE_ENUM) {
1537 field->set_type_name("DummyEnum");
1538 }
1539
1540 // Build the descriptors and get the pointers.
1541 DescriptorPool pool;
1542 const FileDescriptor* file = pool.BuildFile(file_proto);
1543
1544 if (file != NULL &&
1545 file->message_type_count() == 1 &&
1546 file->message_type(0)->field_count() == 1) {
1547 return file->message_type(0)->field(0)->cpp_type();
1548 } else {
1549 return static_cast<FieldDescriptor::CppType>(0);
1550 }
1551 }
1552};
1553
1554TEST_F(MiscTest, CppTypes) {
1555 // Test that CPP types are assigned correctly.
1556
1557 typedef FieldDescriptor FD; // avoid ugly line wrapping
1558
1559 EXPECT_EQ(FD::CPPTYPE_DOUBLE , GetCppTypeForFieldType(FD::TYPE_DOUBLE ));
1560 EXPECT_EQ(FD::CPPTYPE_FLOAT , GetCppTypeForFieldType(FD::TYPE_FLOAT ));
1561 EXPECT_EQ(FD::CPPTYPE_INT64 , GetCppTypeForFieldType(FD::TYPE_INT64 ));
1562 EXPECT_EQ(FD::CPPTYPE_UINT64 , GetCppTypeForFieldType(FD::TYPE_UINT64 ));
1563 EXPECT_EQ(FD::CPPTYPE_INT32 , GetCppTypeForFieldType(FD::TYPE_INT32 ));
1564 EXPECT_EQ(FD::CPPTYPE_UINT64 , GetCppTypeForFieldType(FD::TYPE_FIXED64 ));
1565 EXPECT_EQ(FD::CPPTYPE_UINT32 , GetCppTypeForFieldType(FD::TYPE_FIXED32 ));
1566 EXPECT_EQ(FD::CPPTYPE_BOOL , GetCppTypeForFieldType(FD::TYPE_BOOL ));
1567 EXPECT_EQ(FD::CPPTYPE_STRING , GetCppTypeForFieldType(FD::TYPE_STRING ));
1568 EXPECT_EQ(FD::CPPTYPE_MESSAGE, GetCppTypeForFieldType(FD::TYPE_GROUP ));
1569 EXPECT_EQ(FD::CPPTYPE_MESSAGE, GetCppTypeForFieldType(FD::TYPE_MESSAGE ));
1570 EXPECT_EQ(FD::CPPTYPE_STRING , GetCppTypeForFieldType(FD::TYPE_BYTES ));
1571 EXPECT_EQ(FD::CPPTYPE_UINT32 , GetCppTypeForFieldType(FD::TYPE_UINT32 ));
1572 EXPECT_EQ(FD::CPPTYPE_ENUM , GetCppTypeForFieldType(FD::TYPE_ENUM ));
1573 EXPECT_EQ(FD::CPPTYPE_INT32 , GetCppTypeForFieldType(FD::TYPE_SFIXED32));
1574 EXPECT_EQ(FD::CPPTYPE_INT64 , GetCppTypeForFieldType(FD::TYPE_SFIXED64));
1575 EXPECT_EQ(FD::CPPTYPE_INT32 , GetCppTypeForFieldType(FD::TYPE_SINT32 ));
1576 EXPECT_EQ(FD::CPPTYPE_INT64 , GetCppTypeForFieldType(FD::TYPE_SINT64 ));
1577}
1578
1579TEST_F(MiscTest, DefaultValues) {
1580 // Test that setting default values works.
1581 FileDescriptorProto file_proto;
1582 file_proto.set_name("foo.proto");
1583
1584 EnumDescriptorProto* enum_type_proto = AddEnum(&file_proto, "DummyEnum");
1585 AddEnumValue(enum_type_proto, "A", 1);
1586 AddEnumValue(enum_type_proto, "B", 2);
1587
1588 DescriptorProto* message_proto = AddMessage(&file_proto, "TestMessage");
1589
1590 typedef FieldDescriptorProto FD; // avoid ugly line wrapping
1591 const FD::Label label = FD::LABEL_OPTIONAL;
1592
1593 // Create fields of every CPP type with default values.
1594 AddField(message_proto, "int32" , 1, label, FD::TYPE_INT32 )
1595 ->set_default_value("-1");
1596 AddField(message_proto, "int64" , 2, label, FD::TYPE_INT64 )
1597 ->set_default_value("-1000000000000");
1598 AddField(message_proto, "uint32", 3, label, FD::TYPE_UINT32)
1599 ->set_default_value("42");
1600 AddField(message_proto, "uint64", 4, label, FD::TYPE_UINT64)
1601 ->set_default_value("2000000000000");
1602 AddField(message_proto, "float" , 5, label, FD::TYPE_FLOAT )
1603 ->set_default_value("4.5");
1604 AddField(message_proto, "double", 6, label, FD::TYPE_DOUBLE)
1605 ->set_default_value("10e100");
1606 AddField(message_proto, "bool" , 7, label, FD::TYPE_BOOL )
1607 ->set_default_value("true");
1608 AddField(message_proto, "string", 8, label, FD::TYPE_STRING)
1609 ->set_default_value("hello");
1610 AddField(message_proto, "data" , 9, label, FD::TYPE_BYTES )
1611 ->set_default_value("\\001\\002\\003");
1612
1613 FieldDescriptorProto* enum_field =
1614 AddField(message_proto, "enum", 10, label, FD::TYPE_ENUM);
1615 enum_field->set_type_name("DummyEnum");
1616 enum_field->set_default_value("B");
1617
1618 // Strings are allowed to have empty defaults. (At one point, due to
1619 // a bug, empty defaults for strings were rejected. Oops.)
1620 AddField(message_proto, "empty_string", 11, label, FD::TYPE_STRING)
1621 ->set_default_value("");
1622
1623 // Add a second set of fields with implicit defalut values.
1624 AddField(message_proto, "implicit_int32" , 21, label, FD::TYPE_INT32 );
1625 AddField(message_proto, "implicit_int64" , 22, label, FD::TYPE_INT64 );
1626 AddField(message_proto, "implicit_uint32", 23, label, FD::TYPE_UINT32);
1627 AddField(message_proto, "implicit_uint64", 24, label, FD::TYPE_UINT64);
1628 AddField(message_proto, "implicit_float" , 25, label, FD::TYPE_FLOAT );
1629 AddField(message_proto, "implicit_double", 26, label, FD::TYPE_DOUBLE);
1630 AddField(message_proto, "implicit_bool" , 27, label, FD::TYPE_BOOL );
1631 AddField(message_proto, "implicit_string", 28, label, FD::TYPE_STRING);
1632 AddField(message_proto, "implicit_data" , 29, label, FD::TYPE_BYTES );
1633 AddField(message_proto, "implicit_enum" , 30, label, FD::TYPE_ENUM)
1634 ->set_type_name("DummyEnum");
1635
1636 // Build it.
1637 DescriptorPool pool;
1638 const FileDescriptor* file = pool.BuildFile(file_proto);
1639 ASSERT_TRUE(file != NULL);
1640
1641 ASSERT_EQ(1, file->enum_type_count());
1642 const EnumDescriptor* enum_type = file->enum_type(0);
1643 ASSERT_EQ(2, enum_type->value_count());
1644 const EnumValueDescriptor* enum_value_a = enum_type->value(0);
1645 const EnumValueDescriptor* enum_value_b = enum_type->value(1);
1646
1647 ASSERT_EQ(1, file->message_type_count());
1648 const Descriptor* message = file->message_type(0);
1649
1650 ASSERT_EQ(21, message->field_count());
1651
1652 // Check the default values.
1653 ASSERT_TRUE(message->field(0)->has_default_value());
1654 ASSERT_TRUE(message->field(1)->has_default_value());
1655 ASSERT_TRUE(message->field(2)->has_default_value());
1656 ASSERT_TRUE(message->field(3)->has_default_value());
1657 ASSERT_TRUE(message->field(4)->has_default_value());
1658 ASSERT_TRUE(message->field(5)->has_default_value());
1659 ASSERT_TRUE(message->field(6)->has_default_value());
1660 ASSERT_TRUE(message->field(7)->has_default_value());
1661 ASSERT_TRUE(message->field(8)->has_default_value());
1662 ASSERT_TRUE(message->field(9)->has_default_value());
1663 ASSERT_TRUE(message->field(10)->has_default_value());
1664
1665 EXPECT_EQ(-1 , message->field(0)->default_value_int32 ());
1666 EXPECT_EQ(-GOOGLE_ULONGLONG(1000000000000),
1667 message->field(1)->default_value_int64 ());
1668 EXPECT_EQ(42 , message->field(2)->default_value_uint32());
1669 EXPECT_EQ(GOOGLE_ULONGLONG(2000000000000),
1670 message->field(3)->default_value_uint64());
1671 EXPECT_EQ(4.5 , message->field(4)->default_value_float ());
1672 EXPECT_EQ(10e100 , message->field(5)->default_value_double());
1673 EXPECT_EQ(true , message->field(6)->default_value_bool ());
1674 EXPECT_EQ("hello" , message->field(7)->default_value_string());
1675 EXPECT_EQ("\001\002\003" , message->field(8)->default_value_string());
1676 EXPECT_EQ(enum_value_b , message->field(9)->default_value_enum ());
1677 EXPECT_EQ("" , message->field(10)->default_value_string());
1678
1679 ASSERT_FALSE(message->field(11)->has_default_value());
1680 ASSERT_FALSE(message->field(12)->has_default_value());
1681 ASSERT_FALSE(message->field(13)->has_default_value());
1682 ASSERT_FALSE(message->field(14)->has_default_value());
1683 ASSERT_FALSE(message->field(15)->has_default_value());
1684 ASSERT_FALSE(message->field(16)->has_default_value());
1685 ASSERT_FALSE(message->field(17)->has_default_value());
1686 ASSERT_FALSE(message->field(18)->has_default_value());
1687 ASSERT_FALSE(message->field(19)->has_default_value());
1688 ASSERT_FALSE(message->field(20)->has_default_value());
1689
1690 EXPECT_EQ(0 , message->field(11)->default_value_int32 ());
1691 EXPECT_EQ(0 , message->field(12)->default_value_int64 ());
1692 EXPECT_EQ(0 , message->field(13)->default_value_uint32());
1693 EXPECT_EQ(0 , message->field(14)->default_value_uint64());
1694 EXPECT_EQ(0.0f , message->field(15)->default_value_float ());
1695 EXPECT_EQ(0.0 , message->field(16)->default_value_double());
1696 EXPECT_EQ(false, message->field(17)->default_value_bool ());
1697 EXPECT_EQ("" , message->field(18)->default_value_string());
1698 EXPECT_EQ("" , message->field(19)->default_value_string());
1699 EXPECT_EQ(enum_value_a, message->field(20)->default_value_enum());
1700}
1701
1702TEST_F(MiscTest, FieldOptions) {
1703 // Try setting field options.
1704
1705 FileDescriptorProto file_proto;
1706 file_proto.set_name("foo.proto");
1707
1708 DescriptorProto* message_proto = AddMessage(&file_proto, "TestMessage");
1709 AddField(message_proto, "foo", 1,
1710 FieldDescriptorProto::LABEL_OPTIONAL,
1711 FieldDescriptorProto::TYPE_INT32);
1712 FieldDescriptorProto* bar_proto =
1713 AddField(message_proto, "bar", 2,
1714 FieldDescriptorProto::LABEL_OPTIONAL,
1715 FieldDescriptorProto::TYPE_INT32);
1716
1717 FieldOptions* options = bar_proto->mutable_options();
1718 options->set_ctype(FieldOptions::CORD);
1719
1720 // Build the descriptors and get the pointers.
1721 DescriptorPool pool;
1722 const FileDescriptor* file = pool.BuildFile(file_proto);
1723 ASSERT_TRUE(file != NULL);
1724
1725 ASSERT_EQ(1, file->message_type_count());
1726 const Descriptor* message = file->message_type(0);
1727
1728 ASSERT_EQ(2, message->field_count());
1729 const FieldDescriptor* foo = message->field(0);
1730 const FieldDescriptor* bar = message->field(1);
1731
1732 // "foo" had no options set, so it should return the default options.
1733 EXPECT_EQ(&FieldOptions::default_instance(), &foo->options());
1734
1735 // "bar" had options set.
1736 EXPECT_NE(&FieldOptions::default_instance(), options);
1737 EXPECT_TRUE(bar->options().has_ctype());
1738 EXPECT_EQ(FieldOptions::CORD, bar->options().ctype());
1739}
1740
kenton@google.comd37d46d2009-04-25 02:53:47 +00001741// ===================================================================
1742
1743class AllowUnknownDependenciesTest : public testing::Test {
1744 protected:
1745 virtual void SetUp() {
1746 FileDescriptorProto foo_proto, bar_proto;
1747
1748 pool_.AllowUnknownDependencies();
1749
1750 ASSERT_TRUE(TextFormat::ParseFromString(
1751 "name: 'foo.proto'"
1752 "dependency: 'bar.proto'"
1753 "dependency: 'baz.proto'"
1754 "message_type {"
1755 " name: 'Foo'"
1756 " field { name:'bar' number:1 label:LABEL_OPTIONAL type_name:'Bar' }"
1757 " field { name:'baz' number:2 label:LABEL_OPTIONAL type_name:'Baz' }"
1758 " field { name:'qux' number:3 label:LABEL_OPTIONAL"
1759 " type_name: '.corge.Qux'"
1760 " type: TYPE_ENUM"
1761 " options {"
1762 " uninterpreted_option {"
1763 " name {"
1764 " name_part: 'grault'"
1765 " is_extension: true"
1766 " }"
1767 " positive_int_value: 1234"
1768 " }"
1769 " }"
1770 " }"
1771 "}",
1772 &foo_proto));
1773 ASSERT_TRUE(TextFormat::ParseFromString(
1774 "name: 'bar.proto'"
1775 "message_type { name: 'Bar' }",
1776 &bar_proto));
1777
1778 // Collect pointers to stuff.
1779 bar_file_ = pool_.BuildFile(bar_proto);
1780 ASSERT_TRUE(bar_file_ != NULL);
1781
1782 ASSERT_EQ(1, bar_file_->message_type_count());
1783 bar_type_ = bar_file_->message_type(0);
1784
1785 foo_file_ = pool_.BuildFile(foo_proto);
1786 ASSERT_TRUE(foo_file_ != NULL);
1787
1788 ASSERT_EQ(1, foo_file_->message_type_count());
1789 foo_type_ = foo_file_->message_type(0);
1790
1791 ASSERT_EQ(3, foo_type_->field_count());
1792 bar_field_ = foo_type_->field(0);
1793 baz_field_ = foo_type_->field(1);
1794 qux_field_ = foo_type_->field(2);
1795 }
1796
1797 const FileDescriptor* bar_file_;
1798 const Descriptor* bar_type_;
1799 const FileDescriptor* foo_file_;
1800 const Descriptor* foo_type_;
1801 const FieldDescriptor* bar_field_;
1802 const FieldDescriptor* baz_field_;
1803 const FieldDescriptor* qux_field_;
1804
1805 DescriptorPool pool_;
1806};
1807
1808TEST_F(AllowUnknownDependenciesTest, PlaceholderFile) {
1809 ASSERT_EQ(2, foo_file_->dependency_count());
1810 EXPECT_EQ(bar_file_, foo_file_->dependency(0));
1811
1812 const FileDescriptor* baz_file = foo_file_->dependency(1);
1813 EXPECT_EQ("baz.proto", baz_file->name());
1814 EXPECT_EQ(0, baz_file->message_type_count());
1815
1816 // Placeholder files should not be findable.
1817 EXPECT_EQ(bar_file_, pool_.FindFileByName(bar_file_->name()));
1818 EXPECT_TRUE(pool_.FindFileByName(baz_file->name()) == NULL);
1819}
1820
1821TEST_F(AllowUnknownDependenciesTest, PlaceholderTypes) {
1822 ASSERT_EQ(FieldDescriptor::TYPE_MESSAGE, bar_field_->type());
1823 EXPECT_EQ(bar_type_, bar_field_->message_type());
1824
1825 ASSERT_EQ(FieldDescriptor::TYPE_MESSAGE, baz_field_->type());
1826 const Descriptor* baz_type = baz_field_->message_type();
1827 EXPECT_EQ("Baz", baz_type->name());
1828 EXPECT_EQ("Baz", baz_type->full_name());
1829 EXPECT_EQ("Baz.placeholder.proto", baz_type->file()->name());
1830 EXPECT_EQ(0, baz_type->extension_range_count());
1831
1832 ASSERT_EQ(FieldDescriptor::TYPE_ENUM, qux_field_->type());
1833 const EnumDescriptor* qux_type = qux_field_->enum_type();
1834 EXPECT_EQ("Qux", qux_type->name());
1835 EXPECT_EQ("corge.Qux", qux_type->full_name());
1836 EXPECT_EQ("corge.Qux.placeholder.proto", qux_type->file()->name());
1837
1838 // Placeholder types should not be findable.
1839 EXPECT_EQ(bar_type_, pool_.FindMessageTypeByName(bar_type_->full_name()));
1840 EXPECT_TRUE(pool_.FindMessageTypeByName(baz_type->full_name()) == NULL);
1841 EXPECT_TRUE(pool_.FindEnumTypeByName(qux_type->full_name()) == NULL);
1842}
1843
1844TEST_F(AllowUnknownDependenciesTest, CopyTo) {
1845 // FieldDescriptor::CopyTo() should write non-fully-qualified type names
1846 // for placeholder types which were not originally fully-qualified.
1847 FieldDescriptorProto proto;
1848
1849 // Bar is not a placeholder, so it is fully-qualified.
1850 bar_field_->CopyTo(&proto);
1851 EXPECT_EQ(".Bar", proto.type_name());
1852 EXPECT_EQ(FieldDescriptorProto::TYPE_MESSAGE, proto.type());
1853
1854 // Baz is an unqualified placeholder.
1855 proto.Clear();
1856 baz_field_->CopyTo(&proto);
1857 EXPECT_EQ("Baz", proto.type_name());
1858 EXPECT_FALSE(proto.has_type());
1859
1860 // Qux is a fully-qualified placeholder.
1861 proto.Clear();
1862 qux_field_->CopyTo(&proto);
1863 EXPECT_EQ(".corge.Qux", proto.type_name());
1864 EXPECT_EQ(FieldDescriptorProto::TYPE_ENUM, proto.type());
1865}
1866
1867TEST_F(AllowUnknownDependenciesTest, CustomOptions) {
1868 // Qux should still have the uninterpreted option attached.
1869 ASSERT_EQ(1, qux_field_->options().uninterpreted_option_size());
1870 const UninterpretedOption& option =
1871 qux_field_->options().uninterpreted_option(0);
1872 ASSERT_EQ(1, option.name_size());
1873 EXPECT_EQ("grault", option.name(0).name_part());
1874}
1875
1876TEST_F(AllowUnknownDependenciesTest, UnknownExtendee) {
1877 // Test that we can extend an unknown type. This is slightly tricky because
1878 // it means that the placeholder type must have an extension range.
1879
1880 FileDescriptorProto extension_proto;
1881
1882 ASSERT_TRUE(TextFormat::ParseFromString(
1883 "name: 'extension.proto'"
1884 "extension { extendee: 'UnknownType' name:'some_extension' number:123"
1885 " label:LABEL_OPTIONAL type:TYPE_INT32 }",
1886 &extension_proto));
1887 const FileDescriptor* file = pool_.BuildFile(extension_proto);
1888
1889 ASSERT_TRUE(file != NULL);
1890
1891 ASSERT_EQ(1, file->extension_count());
1892 const Descriptor* extendee = file->extension(0)->containing_type();
1893 EXPECT_EQ("UnknownType", extendee->name());
1894 ASSERT_EQ(1, extendee->extension_range_count());
1895 EXPECT_EQ(1, extendee->extension_range(0)->start);
1896 EXPECT_EQ(FieldDescriptor::kMaxNumber + 1, extendee->extension_range(0)->end);
1897}
1898
1899TEST_F(AllowUnknownDependenciesTest, CustomOption) {
1900 // Test that we can use a custom option without having parsed
1901 // descriptor.proto.
1902
1903 FileDescriptorProto option_proto;
1904
1905 ASSERT_TRUE(TextFormat::ParseFromString(
1906 "name: \"unknown_custom_options.proto\" "
1907 "dependency: \"google/protobuf/descriptor.proto\" "
1908 "extension { "
1909 " extendee: \"google.protobuf.FileOptions\" "
1910 " name: \"some_option\" "
1911 " number: 123456 "
1912 " label: LABEL_OPTIONAL "
1913 " type: TYPE_INT32 "
1914 "} "
1915 "options { "
1916 " uninterpreted_option { "
1917 " name { "
1918 " name_part: \"some_option\" "
1919 " is_extension: true "
1920 " } "
1921 " positive_int_value: 1234 "
1922 " } "
1923 " uninterpreted_option { "
1924 " name { "
1925 " name_part: \"unknown_option\" "
1926 " is_extension: true "
1927 " } "
1928 " positive_int_value: 1234 "
1929 " } "
1930 " uninterpreted_option { "
1931 " name { "
1932 " name_part: \"optimize_for\" "
1933 " is_extension: false "
1934 " } "
1935 " identifier_value: \"SPEED\" "
1936 " } "
1937 "}",
1938 &option_proto));
1939
1940 const FileDescriptor* file = pool_.BuildFile(option_proto);
1941 ASSERT_TRUE(file != NULL);
1942
1943 // Verify that no extension options were set, but they were left as
1944 // uninterpreted_options.
1945 vector<const FieldDescriptor*> fields;
1946 file->options().GetReflection()->ListFields(file->options(), &fields);
1947 ASSERT_EQ(2, fields.size());
1948 EXPECT_TRUE(file->options().has_optimize_for());
1949 EXPECT_EQ(2, file->options().uninterpreted_option_size());
1950}
1951
1952// ===================================================================
1953
kenton@google.com24bf56f2008-09-24 20:31:01 +00001954TEST(CustomOptions, OptionLocations) {
1955 const Descriptor* message =
1956 protobuf_unittest::TestMessageWithCustomOptions::descriptor();
1957 const FileDescriptor* file = message->file();
1958 const FieldDescriptor* field = message->FindFieldByName("field1");
1959 const EnumDescriptor* enm = message->FindEnumTypeByName("AnEnum");
1960 // TODO(benjy): Support EnumValue options, once the compiler does.
1961 const ServiceDescriptor* service =
1962 file->FindServiceByName("TestServiceWithCustomOptions");
1963 const MethodDescriptor* method = service->FindMethodByName("Foo");
1964
1965 EXPECT_EQ(GOOGLE_LONGLONG(9876543210),
1966 file->options().GetExtension(protobuf_unittest::file_opt1));
1967 EXPECT_EQ(-56,
1968 message->options().GetExtension(protobuf_unittest::message_opt1));
1969 EXPECT_EQ(GOOGLE_LONGLONG(8765432109),
1970 field->options().GetExtension(protobuf_unittest::field_opt1));
1971 EXPECT_EQ(42, // Check that we get the default for an option we don't set.
1972 field->options().GetExtension(protobuf_unittest::field_opt2));
1973 EXPECT_EQ(-789,
1974 enm->options().GetExtension(protobuf_unittest::enum_opt1));
kenton@google.com1ea52682008-12-02 20:08:45 +00001975 EXPECT_EQ(123,
1976 enm->value(1)->options().GetExtension(
1977 protobuf_unittest::enum_value_opt1));
kenton@google.com24bf56f2008-09-24 20:31:01 +00001978 EXPECT_EQ(GOOGLE_LONGLONG(-9876543210),
1979 service->options().GetExtension(protobuf_unittest::service_opt1));
1980 EXPECT_EQ(protobuf_unittest::METHODOPT1_VAL2,
1981 method->options().GetExtension(protobuf_unittest::method_opt1));
1982
1983 // See that the regular options went through unscathed.
1984 EXPECT_TRUE(message->options().has_message_set_wire_format());
1985 EXPECT_EQ(FieldOptions::CORD, field->options().ctype());
1986}
1987
1988TEST(CustomOptions, OptionTypes) {
1989 const MessageOptions* options = NULL;
1990
1991 options =
1992 &protobuf_unittest::CustomOptionMinIntegerValues::descriptor()->options();
1993 EXPECT_EQ(false , options->GetExtension(protobuf_unittest::bool_opt));
1994 EXPECT_EQ(kint32min, options->GetExtension(protobuf_unittest::int32_opt));
1995 EXPECT_EQ(kint64min, options->GetExtension(protobuf_unittest::int64_opt));
1996 EXPECT_EQ(0 , options->GetExtension(protobuf_unittest::uint32_opt));
1997 EXPECT_EQ(0 , options->GetExtension(protobuf_unittest::uint64_opt));
1998 EXPECT_EQ(kint32min, options->GetExtension(protobuf_unittest::sint32_opt));
1999 EXPECT_EQ(kint64min, options->GetExtension(protobuf_unittest::sint64_opt));
2000 EXPECT_EQ(0 , options->GetExtension(protobuf_unittest::fixed32_opt));
2001 EXPECT_EQ(0 , options->GetExtension(protobuf_unittest::fixed64_opt));
2002 EXPECT_EQ(kint32min, options->GetExtension(protobuf_unittest::sfixed32_opt));
2003 EXPECT_EQ(kint64min, options->GetExtension(protobuf_unittest::sfixed64_opt));
2004
2005 options =
2006 &protobuf_unittest::CustomOptionMaxIntegerValues::descriptor()->options();
2007 EXPECT_EQ(true , options->GetExtension(protobuf_unittest::bool_opt));
2008 EXPECT_EQ(kint32max , options->GetExtension(protobuf_unittest::int32_opt));
2009 EXPECT_EQ(kint64max , options->GetExtension(protobuf_unittest::int64_opt));
2010 EXPECT_EQ(kuint32max, options->GetExtension(protobuf_unittest::uint32_opt));
2011 EXPECT_EQ(kuint64max, options->GetExtension(protobuf_unittest::uint64_opt));
2012 EXPECT_EQ(kint32max , options->GetExtension(protobuf_unittest::sint32_opt));
2013 EXPECT_EQ(kint64max , options->GetExtension(protobuf_unittest::sint64_opt));
2014 EXPECT_EQ(kuint32max, options->GetExtension(protobuf_unittest::fixed32_opt));
2015 EXPECT_EQ(kuint64max, options->GetExtension(protobuf_unittest::fixed64_opt));
2016 EXPECT_EQ(kint32max , options->GetExtension(protobuf_unittest::sfixed32_opt));
2017 EXPECT_EQ(kint64max , options->GetExtension(protobuf_unittest::sfixed64_opt));
2018
2019 options =
2020 &protobuf_unittest::CustomOptionOtherValues::descriptor()->options();
2021 EXPECT_EQ(-100, options->GetExtension(protobuf_unittest::int32_opt));
2022 EXPECT_FLOAT_EQ(12.3456789,
2023 options->GetExtension(protobuf_unittest::float_opt));
2024 EXPECT_DOUBLE_EQ(1.234567890123456789,
2025 options->GetExtension(protobuf_unittest::double_opt));
2026 EXPECT_EQ("Hello, \"World\"",
2027 options->GetExtension(protobuf_unittest::string_opt));
2028
2029 EXPECT_EQ(string("Hello\0World", 11),
2030 options->GetExtension(protobuf_unittest::bytes_opt));
2031
2032 EXPECT_EQ(protobuf_unittest::DummyMessageContainingEnum::TEST_OPTION_ENUM_TYPE2,
2033 options->GetExtension(protobuf_unittest::enum_opt));
2034
2035 options =
2036 &protobuf_unittest::SettingRealsFromPositiveInts::descriptor()->options();
2037 EXPECT_FLOAT_EQ(12, options->GetExtension(protobuf_unittest::float_opt));
2038 EXPECT_DOUBLE_EQ(154, options->GetExtension(protobuf_unittest::double_opt));
2039
2040 options =
2041 &protobuf_unittest::SettingRealsFromNegativeInts::descriptor()->options();
2042 EXPECT_FLOAT_EQ(-12, options->GetExtension(protobuf_unittest::float_opt));
2043 EXPECT_DOUBLE_EQ(-154, options->GetExtension(protobuf_unittest::double_opt));
2044}
2045
2046TEST(CustomOptions, ComplexExtensionOptions) {
2047 const MessageOptions* options =
2048 &protobuf_unittest::VariousComplexOptions::descriptor()->options();
2049 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt1).foo(), 42);
2050 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt1).
2051 GetExtension(protobuf_unittest::quux), 324);
2052 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt1).
2053 GetExtension(protobuf_unittest::corge).qux(), 876);
2054 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2).baz(), 987);
2055 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2).
2056 GetExtension(protobuf_unittest::grault), 654);
2057 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2).bar().foo(),
2058 743);
2059 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2).bar().
2060 GetExtension(protobuf_unittest::quux), 1999);
2061 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2).bar().
2062 GetExtension(protobuf_unittest::corge).qux(), 2008);
2063 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2).
2064 GetExtension(protobuf_unittest::garply).foo(), 741);
2065 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2).
2066 GetExtension(protobuf_unittest::garply).
2067 GetExtension(protobuf_unittest::quux), 1998);
2068 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2).
2069 GetExtension(protobuf_unittest::garply).
2070 GetExtension(protobuf_unittest::corge).qux(), 2121);
2071 EXPECT_EQ(options->GetExtension(
2072 protobuf_unittest::ComplexOptionType2::ComplexOptionType4::complex_opt4).
2073 waldo(), 1971);
2074 EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2).
2075 fred().waldo(), 321);
2076 EXPECT_EQ(9, options->GetExtension(protobuf_unittest::complex_opt3).qux());
2077 EXPECT_EQ(22, options->GetExtension(protobuf_unittest::complex_opt3).
2078 complexoptiontype5().plugh());
2079 EXPECT_EQ(24, options->GetExtension(protobuf_unittest::complexopt6).xyzzy());
2080}
2081
kenton@google.com26bd9ee2008-11-21 00:06:27 +00002082TEST(CustomOptions, OptionsFromOtherFile) {
2083 // Test that to use a custom option, we only need to import the file
2084 // defining the option; we do not also have to import descriptor.proto.
2085 DescriptorPool pool;
2086
2087 FileDescriptorProto file_proto;
2088 FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto);
2089 ASSERT_TRUE(pool.BuildFile(file_proto) != NULL);
2090
2091 protobuf_unittest::TestMessageWithCustomOptions::descriptor()
2092 ->file()->CopyTo(&file_proto);
2093 ASSERT_TRUE(pool.BuildFile(file_proto) != NULL);
2094
2095 ASSERT_TRUE(TextFormat::ParseFromString(
2096 "name: \"custom_options_import.proto\" "
2097 "package: \"protobuf_unittest\" "
2098 "dependency: \"google/protobuf/unittest_custom_options.proto\" "
2099 "options { "
2100 " uninterpreted_option { "
2101 " name { "
2102 " name_part: \"file_opt1\" "
2103 " is_extension: true "
2104 " } "
2105 " positive_int_value: 1234 "
2106 " } "
2107 // Test a non-extension option too. (At one point this failed due to a
2108 // bug.)
2109 " uninterpreted_option { "
2110 " name { "
2111 " name_part: \"java_package\" "
2112 " is_extension: false "
2113 " } "
2114 " string_value: \"foo\" "
2115 " } "
2116 // Test that enum-typed options still work too. (At one point this also
2117 // failed due to a bug.)
2118 " uninterpreted_option { "
2119 " name { "
2120 " name_part: \"optimize_for\" "
2121 " is_extension: false "
2122 " } "
2123 " identifier_value: \"SPEED\" "
2124 " } "
2125 "}"
2126 ,
2127 &file_proto));
2128
2129 const FileDescriptor* file = pool.BuildFile(file_proto);
2130 ASSERT_TRUE(file != NULL);
2131 EXPECT_EQ(1234, file->options().GetExtension(protobuf_unittest::file_opt1));
2132 EXPECT_TRUE(file->options().has_java_package());
2133 EXPECT_EQ("foo", file->options().java_package());
2134 EXPECT_TRUE(file->options().has_optimize_for());
2135 EXPECT_EQ(FileOptions::SPEED, file->options().optimize_for());
2136}
kenton@google.com24bf56f2008-09-24 20:31:01 +00002137
kenton@google.com80b1d622009-07-29 01:13:20 +00002138TEST(CustomOptions, MessageOptionThreeFieldsSet) {
2139 // This tests a bug which previously existed in custom options parsing. The
2140 // bug occurred when you defined a custom option with message type and then
2141 // set three fields of that option on a single definition (see the example
2142 // below). The bug is a bit hard to explain, so check the change history if
2143 // you want to know more.
2144 DescriptorPool pool;
2145
2146 FileDescriptorProto file_proto;
2147 FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto);
2148 ASSERT_TRUE(pool.BuildFile(file_proto) != NULL);
2149
2150 protobuf_unittest::TestMessageWithCustomOptions::descriptor()
2151 ->file()->CopyTo(&file_proto);
2152 ASSERT_TRUE(pool.BuildFile(file_proto) != NULL);
2153
2154 // The following represents the definition:
2155 //
2156 // import "google/protobuf/unittest_custom_options.proto"
2157 // package protobuf_unittest;
2158 // message Foo {
2159 // option (complex_opt1).foo = 1234;
2160 // option (complex_opt1).foo2 = 1234;
2161 // option (complex_opt1).foo3 = 1234;
2162 // }
2163 ASSERT_TRUE(TextFormat::ParseFromString(
2164 "name: \"custom_options_import.proto\" "
2165 "package: \"protobuf_unittest\" "
2166 "dependency: \"google/protobuf/unittest_custom_options.proto\" "
2167 "message_type { "
2168 " name: \"Foo\" "
2169 " options { "
2170 " uninterpreted_option { "
2171 " name { "
2172 " name_part: \"complex_opt1\" "
2173 " is_extension: true "
2174 " } "
2175 " name { "
2176 " name_part: \"foo\" "
2177 " is_extension: false "
2178 " } "
2179 " positive_int_value: 1234 "
2180 " } "
2181 " uninterpreted_option { "
2182 " name { "
2183 " name_part: \"complex_opt1\" "
2184 " is_extension: true "
2185 " } "
2186 " name { "
2187 " name_part: \"foo2\" "
2188 " is_extension: false "
2189 " } "
2190 " positive_int_value: 1234 "
2191 " } "
2192 " uninterpreted_option { "
2193 " name { "
2194 " name_part: \"complex_opt1\" "
2195 " is_extension: true "
2196 " } "
2197 " name { "
2198 " name_part: \"foo3\" "
2199 " is_extension: false "
2200 " } "
2201 " positive_int_value: 1234 "
2202 " } "
2203 " } "
2204 "}",
2205 &file_proto));
2206
2207 const FileDescriptor* file = pool.BuildFile(file_proto);
2208 ASSERT_TRUE(file != NULL);
2209 ASSERT_EQ(1, file->message_type_count());
2210
2211 const MessageOptions& options = file->message_type(0)->options();
2212 EXPECT_EQ(1234, options.GetExtension(protobuf_unittest::complex_opt1).foo());
2213}
2214
liujisi@google.com33165fe2010-11-02 13:14:58 +00002215// Check that aggregate options were parsed and saved correctly in
2216// the appropriate descriptors.
2217TEST(CustomOptions, AggregateOptions) {
2218 const Descriptor* msg = protobuf_unittest::AggregateMessage::descriptor();
2219 const FileDescriptor* file = msg->file();
2220 const FieldDescriptor* field = msg->FindFieldByName("fieldname");
2221 const EnumDescriptor* enumd = file->FindEnumTypeByName("AggregateEnum");
2222 const EnumValueDescriptor* enumv = enumd->FindValueByName("VALUE");
2223 const ServiceDescriptor* service = file->FindServiceByName(
2224 "AggregateService");
2225 const MethodDescriptor* method = service->FindMethodByName("Method");
2226
2227 // Tests for the different types of data embedded in fileopt
2228 const protobuf_unittest::Aggregate& file_options =
2229 file->options().GetExtension(protobuf_unittest::fileopt);
2230 EXPECT_EQ(100, file_options.i());
2231 EXPECT_EQ("FileAnnotation", file_options.s());
2232 EXPECT_EQ("NestedFileAnnotation", file_options.sub().s());
2233 EXPECT_EQ("FileExtensionAnnotation",
2234 file_options.file().GetExtension(protobuf_unittest::fileopt).s());
2235 EXPECT_EQ("EmbeddedMessageSetElement",
2236 file_options.mset().GetExtension(
2237 protobuf_unittest::AggregateMessageSetElement
2238 ::message_set_extension).s());
2239
2240 // Simple tests for all the other types of annotations
2241 EXPECT_EQ("MessageAnnotation",
2242 msg->options().GetExtension(protobuf_unittest::msgopt).s());
2243 EXPECT_EQ("FieldAnnotation",
2244 field->options().GetExtension(protobuf_unittest::fieldopt).s());
2245 EXPECT_EQ("EnumAnnotation",
2246 enumd->options().GetExtension(protobuf_unittest::enumopt).s());
2247 EXPECT_EQ("EnumValueAnnotation",
2248 enumv->options().GetExtension(protobuf_unittest::enumvalopt).s());
2249 EXPECT_EQ("ServiceAnnotation",
2250 service->options().GetExtension(protobuf_unittest::serviceopt).s());
2251 EXPECT_EQ("MethodAnnotation",
2252 method->options().GetExtension(protobuf_unittest::methodopt).s());
2253}
kenton@google.com24bf56f2008-09-24 20:31:01 +00002254
temporal40ee5512008-07-10 02:12:20 +00002255// ===================================================================
2256
2257// The tests below trigger every unique call to AddError() in descriptor.cc,
2258// in the order in which they appear in that file. I'm using TextFormat here
2259// to specify the input descriptors because building them using code would
2260// be too bulky.
2261
2262class MockErrorCollector : public DescriptorPool::ErrorCollector {
2263 public:
2264 MockErrorCollector() {}
2265 ~MockErrorCollector() {}
2266
2267 string text_;
2268
2269 // implements ErrorCollector ---------------------------------------
2270 void AddError(const string& filename,
2271 const string& element_name, const Message* descriptor,
2272 ErrorLocation location, const string& message) {
2273 const char* location_name = NULL;
2274 switch (location) {
2275 case NAME : location_name = "NAME" ; break;
2276 case NUMBER : location_name = "NUMBER" ; break;
2277 case TYPE : location_name = "TYPE" ; break;
2278 case EXTENDEE : location_name = "EXTENDEE" ; break;
2279 case DEFAULT_VALUE: location_name = "DEFAULT_VALUE"; break;
kenton@google.com24bf56f2008-09-24 20:31:01 +00002280 case OPTION_NAME : location_name = "OPTION_NAME" ; break;
2281 case OPTION_VALUE : location_name = "OPTION_VALUE" ; break;
temporal40ee5512008-07-10 02:12:20 +00002282 case INPUT_TYPE : location_name = "INPUT_TYPE" ; break;
2283 case OUTPUT_TYPE : location_name = "OUTPUT_TYPE" ; break;
2284 case OTHER : location_name = "OTHER" ; break;
2285 }
2286
2287 strings::SubstituteAndAppend(
2288 &text_, "$0: $1: $2: $3\n",
2289 filename, element_name, location_name, message);
2290 }
2291};
2292
2293class ValidationErrorTest : public testing::Test {
2294 protected:
2295 // Parse file_text as a FileDescriptorProto in text format and add it
2296 // to the DescriptorPool. Expect no errors.
2297 void BuildFile(const string& file_text) {
2298 FileDescriptorProto file_proto;
2299 ASSERT_TRUE(TextFormat::ParseFromString(file_text, &file_proto));
2300 ASSERT_TRUE(pool_.BuildFile(file_proto) != NULL);
2301 }
2302
2303 // Parse file_text as a FileDescriptorProto in text format and add it
2304 // to the DescriptorPool. Expect errors to be produced which match the
2305 // given error text.
2306 void BuildFileWithErrors(const string& file_text,
2307 const string& expected_errors) {
2308 FileDescriptorProto file_proto;
2309 ASSERT_TRUE(TextFormat::ParseFromString(file_text, &file_proto));
2310
2311 MockErrorCollector error_collector;
2312 EXPECT_TRUE(
2313 pool_.BuildFileCollectingErrors(file_proto, &error_collector) == NULL);
2314 EXPECT_EQ(expected_errors, error_collector.text_);
2315 }
2316
kenton@google.com24bf56f2008-09-24 20:31:01 +00002317 // Builds some already-parsed file in our test pool.
2318 void BuildFileInTestPool(const FileDescriptor* file) {
2319 FileDescriptorProto file_proto;
2320 file->CopyTo(&file_proto);
2321 ASSERT_TRUE(pool_.BuildFile(file_proto) != NULL);
2322 }
2323
2324 // Build descriptor.proto in our test pool. This allows us to extend it in
2325 // the test pool, so we can test custom options.
2326 void BuildDescriptorMessagesInTestPool() {
2327 BuildFileInTestPool(DescriptorProto::descriptor()->file());
2328 }
2329
temporal40ee5512008-07-10 02:12:20 +00002330 DescriptorPool pool_;
2331};
2332
2333TEST_F(ValidationErrorTest, AlreadyDefined) {
2334 BuildFileWithErrors(
2335 "name: \"foo.proto\" "
2336 "message_type { name: \"Foo\" }"
2337 "message_type { name: \"Foo\" }",
2338
2339 "foo.proto: Foo: NAME: \"Foo\" is already defined.\n");
2340}
2341
2342TEST_F(ValidationErrorTest, AlreadyDefinedInPackage) {
2343 BuildFileWithErrors(
2344 "name: \"foo.proto\" "
2345 "package: \"foo.bar\" "
2346 "message_type { name: \"Foo\" }"
2347 "message_type { name: \"Foo\" }",
2348
2349 "foo.proto: foo.bar.Foo: NAME: \"Foo\" is already defined in "
2350 "\"foo.bar\".\n");
2351}
2352
2353TEST_F(ValidationErrorTest, AlreadyDefinedInOtherFile) {
2354 BuildFile(
2355 "name: \"foo.proto\" "
2356 "message_type { name: \"Foo\" }");
2357
2358 BuildFileWithErrors(
2359 "name: \"bar.proto\" "
2360 "message_type { name: \"Foo\" }",
2361
2362 "bar.proto: Foo: NAME: \"Foo\" is already defined in file "
2363 "\"foo.proto\".\n");
2364}
2365
2366TEST_F(ValidationErrorTest, PackageAlreadyDefined) {
2367 BuildFile(
2368 "name: \"foo.proto\" "
2369 "message_type { name: \"foo\" }");
2370 BuildFileWithErrors(
2371 "name: \"bar.proto\" "
2372 "package: \"foo.bar\"",
2373
2374 "bar.proto: foo: NAME: \"foo\" is already defined (as something other "
2375 "than a package) in file \"foo.proto\".\n");
2376}
2377
temporalf2063512008-07-23 01:19:07 +00002378TEST_F(ValidationErrorTest, EnumValueAlreadyDefinedInParent) {
2379 BuildFileWithErrors(
2380 "name: \"foo.proto\" "
2381 "enum_type { name: \"Foo\" value { name: \"FOO\" number: 1 } } "
2382 "enum_type { name: \"Bar\" value { name: \"FOO\" number: 1 } } ",
2383
2384 "foo.proto: FOO: NAME: \"FOO\" is already defined.\n"
2385 "foo.proto: FOO: NAME: Note that enum values use C++ scoping rules, "
2386 "meaning that enum values are siblings of their type, not children of "
2387 "it. Therefore, \"FOO\" must be unique within the global scope, not "
2388 "just within \"Bar\".\n");
2389}
2390
2391TEST_F(ValidationErrorTest, EnumValueAlreadyDefinedInParentNonGlobal) {
2392 BuildFileWithErrors(
2393 "name: \"foo.proto\" "
2394 "package: \"pkg\" "
2395 "enum_type { name: \"Foo\" value { name: \"FOO\" number: 1 } } "
2396 "enum_type { name: \"Bar\" value { name: \"FOO\" number: 1 } } ",
2397
2398 "foo.proto: pkg.FOO: NAME: \"FOO\" is already defined in \"pkg\".\n"
2399 "foo.proto: pkg.FOO: NAME: Note that enum values use C++ scoping rules, "
2400 "meaning that enum values are siblings of their type, not children of "
2401 "it. Therefore, \"FOO\" must be unique within \"pkg\", not just within "
2402 "\"Bar\".\n");
2403}
2404
temporal40ee5512008-07-10 02:12:20 +00002405TEST_F(ValidationErrorTest, MissingName) {
2406 BuildFileWithErrors(
2407 "name: \"foo.proto\" "
2408 "message_type { }",
2409
2410 "foo.proto: : NAME: Missing name.\n");
2411}
2412
2413TEST_F(ValidationErrorTest, InvalidName) {
2414 BuildFileWithErrors(
2415 "name: \"foo.proto\" "
2416 "message_type { name: \"$\" }",
2417
2418 "foo.proto: $: NAME: \"$\" is not a valid identifier.\n");
2419}
2420
2421TEST_F(ValidationErrorTest, InvalidPackageName) {
2422 BuildFileWithErrors(
2423 "name: \"foo.proto\" "
2424 "package: \"foo.$\"",
2425
2426 "foo.proto: foo.$: NAME: \"$\" is not a valid identifier.\n");
2427}
2428
2429TEST_F(ValidationErrorTest, MissingFileName) {
2430 BuildFileWithErrors(
2431 "",
2432
2433 ": : OTHER: Missing field: FileDescriptorProto.name.\n");
2434}
2435
2436TEST_F(ValidationErrorTest, DupeDependency) {
2437 BuildFile("name: \"foo.proto\"");
2438 BuildFileWithErrors(
2439 "name: \"bar.proto\" "
2440 "dependency: \"foo.proto\" "
2441 "dependency: \"foo.proto\" ",
2442
2443 "bar.proto: bar.proto: OTHER: Import \"foo.proto\" was listed twice.\n");
2444}
2445
2446TEST_F(ValidationErrorTest, UnknownDependency) {
2447 BuildFileWithErrors(
2448 "name: \"bar.proto\" "
2449 "dependency: \"foo.proto\" ",
2450
2451 "bar.proto: bar.proto: OTHER: Import \"foo.proto\" has not been loaded.\n");
2452}
2453
kenton@google.com80b1d622009-07-29 01:13:20 +00002454TEST_F(ValidationErrorTest, ForeignUnimportedPackageNoCrash) {
2455 // Used to crash: If we depend on a non-existent file and then refer to a
2456 // package defined in a file that we didn't import, and that package is
2457 // nested within a parent package which this file is also in, and we don't
2458 // include that parent package in the name (i.e. we do a relative lookup)...
2459 // Yes, really.
2460 BuildFile(
2461 "name: 'foo.proto' "
2462 "package: 'outer.foo' ");
2463 BuildFileWithErrors(
2464 "name: 'bar.proto' "
2465 "dependency: 'baz.proto' "
2466 "package: 'outer.bar' "
2467 "message_type { "
2468 " name: 'Bar' "
2469 " field { name:'bar' number:1 label:LABEL_OPTIONAL type_name:'foo.Foo' }"
2470 "}",
2471
2472 "bar.proto: bar.proto: OTHER: Import \"baz.proto\" has not been loaded.\n"
2473 "bar.proto: outer.bar.Bar.bar: TYPE: \"outer.foo\" seems to be defined in "
2474 "\"foo.proto\", which is not imported by \"bar.proto\". To use it here, "
2475 "please add the necessary import.\n");
2476}
2477
temporal40ee5512008-07-10 02:12:20 +00002478TEST_F(ValidationErrorTest, DupeFile) {
2479 BuildFile(
2480 "name: \"foo.proto\" "
2481 "message_type { name: \"Foo\" }");
2482 // Note: We should *not* get redundant errors about "Foo" already being
2483 // defined.
2484 BuildFileWithErrors(
2485 "name: \"foo.proto\" "
kenton@google.comd37d46d2009-04-25 02:53:47 +00002486 "message_type { name: \"Foo\" } "
2487 // Add another type so that the files aren't identical (in which case there
2488 // would be no error).
2489 "enum_type { name: \"Bar\" }",
temporal40ee5512008-07-10 02:12:20 +00002490
2491 "foo.proto: foo.proto: OTHER: A file with this name is already in the "
2492 "pool.\n");
2493}
2494
2495TEST_F(ValidationErrorTest, FieldInExtensionRange) {
2496 BuildFileWithErrors(
2497 "name: \"foo.proto\" "
2498 "message_type {"
2499 " name: \"Foo\""
2500 " field { name: \"foo\" number: 9 label:LABEL_OPTIONAL type:TYPE_INT32 }"
2501 " field { name: \"bar\" number: 10 label:LABEL_OPTIONAL type:TYPE_INT32 }"
2502 " field { name: \"baz\" number: 19 label:LABEL_OPTIONAL type:TYPE_INT32 }"
2503 " field { name: \"qux\" number: 20 label:LABEL_OPTIONAL type:TYPE_INT32 }"
2504 " extension_range { start: 10 end: 20 }"
2505 "}",
2506
2507 "foo.proto: Foo.bar: NUMBER: Extension range 10 to 19 includes field "
2508 "\"bar\" (10).\n"
2509 "foo.proto: Foo.baz: NUMBER: Extension range 10 to 19 includes field "
2510 "\"baz\" (19).\n");
2511}
2512
2513TEST_F(ValidationErrorTest, OverlappingExtensionRanges) {
2514 BuildFileWithErrors(
2515 "name: \"foo.proto\" "
2516 "message_type {"
2517 " name: \"Foo\""
2518 " extension_range { start: 10 end: 20 }"
2519 " extension_range { start: 20 end: 30 }"
2520 " extension_range { start: 19 end: 21 }"
2521 "}",
2522
2523 "foo.proto: Foo: NUMBER: Extension range 19 to 20 overlaps with "
2524 "already-defined range 10 to 19.\n"
2525 "foo.proto: Foo: NUMBER: Extension range 19 to 20 overlaps with "
2526 "already-defined range 20 to 29.\n");
2527}
2528
2529TEST_F(ValidationErrorTest, InvalidDefaults) {
2530 BuildFileWithErrors(
2531 "name: \"foo.proto\" "
2532 "message_type {"
2533 " name: \"Foo\""
2534
2535 // Invalid number.
2536 " field { name: \"foo\" number: 1 label: LABEL_OPTIONAL type: TYPE_INT32"
2537 " default_value: \"abc\" }"
2538
2539 // Empty default value.
2540 " field { name: \"bar\" number: 2 label: LABEL_OPTIONAL type: TYPE_INT32"
2541 " default_value: \"\" }"
2542
2543 // Invalid boolean.
2544 " field { name: \"baz\" number: 3 label: LABEL_OPTIONAL type: TYPE_BOOL"
2545 " default_value: \"abc\" }"
2546
2547 // Messages can't have defaults.
2548 " field { name: \"qux\" number: 4 label: LABEL_OPTIONAL type: TYPE_MESSAGE"
2549 " default_value: \"abc\" type_name: \"Foo\" }"
2550
2551 // Same thing, but we don't know that this field has message type until
2552 // we look up the type name.
2553 " field { name: \"quux\" number: 5 label: LABEL_OPTIONAL"
2554 " default_value: \"abc\" type_name: \"Foo\" }"
kenton@google.comd37d46d2009-04-25 02:53:47 +00002555
2556 // Repeateds can't have defaults.
2557 " field { name: \"corge\" number: 6 label: LABEL_REPEATED type: TYPE_INT32"
2558 " default_value: \"1\" }"
temporal40ee5512008-07-10 02:12:20 +00002559 "}",
2560
2561 "foo.proto: Foo.foo: DEFAULT_VALUE: Couldn't parse default value.\n"
2562 "foo.proto: Foo.bar: DEFAULT_VALUE: Couldn't parse default value.\n"
2563 "foo.proto: Foo.baz: DEFAULT_VALUE: Boolean default must be true or "
2564 "false.\n"
2565 "foo.proto: Foo.qux: DEFAULT_VALUE: Messages can't have default values.\n"
kenton@google.comd37d46d2009-04-25 02:53:47 +00002566 "foo.proto: Foo.corge: DEFAULT_VALUE: Repeated fields can't have default "
2567 "values.\n"
2568 // This ends up being reported later because the error is detected at
2569 // cross-linking time.
temporal40ee5512008-07-10 02:12:20 +00002570 "foo.proto: Foo.quux: DEFAULT_VALUE: Messages can't have default "
2571 "values.\n");
2572}
2573
2574TEST_F(ValidationErrorTest, NegativeFieldNumber) {
2575 BuildFileWithErrors(
2576 "name: \"foo.proto\" "
2577 "message_type {"
2578 " name: \"Foo\""
2579 " field { name: \"foo\" number: -1 label:LABEL_OPTIONAL type:TYPE_INT32 }"
2580 "}",
2581
2582 "foo.proto: Foo.foo: NUMBER: Field numbers must be positive integers.\n");
2583}
2584
2585TEST_F(ValidationErrorTest, HugeFieldNumber) {
2586 BuildFileWithErrors(
2587 "name: \"foo.proto\" "
2588 "message_type {"
2589 " name: \"Foo\""
2590 " field { name: \"foo\" number: 0x70000000 "
2591 " label:LABEL_OPTIONAL type:TYPE_INT32 }"
2592 "}",
2593
2594 "foo.proto: Foo.foo: NUMBER: Field numbers cannot be greater than "
2595 "536870911.\n");
2596}
2597
2598TEST_F(ValidationErrorTest, ReservedFieldNumber) {
2599 BuildFileWithErrors(
2600 "name: \"foo.proto\" "
2601 "message_type {"
2602 " name: \"Foo\""
2603 " field {name:\"foo\" number: 18999 label:LABEL_OPTIONAL type:TYPE_INT32 }"
2604 " field {name:\"bar\" number: 19000 label:LABEL_OPTIONAL type:TYPE_INT32 }"
2605 " field {name:\"baz\" number: 19999 label:LABEL_OPTIONAL type:TYPE_INT32 }"
2606 " field {name:\"qux\" number: 20000 label:LABEL_OPTIONAL type:TYPE_INT32 }"
2607 "}",
2608
2609 "foo.proto: Foo.bar: NUMBER: Field numbers 19000 through 19999 are "
2610 "reserved for the protocol buffer library implementation.\n"
2611 "foo.proto: Foo.baz: NUMBER: Field numbers 19000 through 19999 are "
2612 "reserved for the protocol buffer library implementation.\n");
2613}
2614
2615TEST_F(ValidationErrorTest, ExtensionMissingExtendee) {
2616 BuildFileWithErrors(
2617 "name: \"foo.proto\" "
2618 "message_type {"
2619 " name: \"Foo\""
2620 " extension { name: \"foo\" number: 1 label: LABEL_OPTIONAL"
2621 " type_name: \"Foo\" }"
2622 "}",
2623
2624 "foo.proto: Foo.foo: EXTENDEE: FieldDescriptorProto.extendee not set for "
2625 "extension field.\n");
2626}
2627
2628TEST_F(ValidationErrorTest, NonExtensionWithExtendee) {
2629 BuildFileWithErrors(
2630 "name: \"foo.proto\" "
2631 "message_type {"
2632 " name: \"Bar\""
2633 " extension_range { start: 1 end: 2 }"
2634 "}"
2635 "message_type {"
2636 " name: \"Foo\""
2637 " field { name: \"foo\" number: 1 label: LABEL_OPTIONAL"
2638 " type_name: \"Foo\" extendee: \"Bar\" }"
2639 "}",
2640
2641 "foo.proto: Foo.foo: EXTENDEE: FieldDescriptorProto.extendee set for "
2642 "non-extension field.\n");
2643}
2644
2645TEST_F(ValidationErrorTest, FieldNumberConflict) {
2646 BuildFileWithErrors(
2647 "name: \"foo.proto\" "
2648 "message_type {"
2649 " name: \"Foo\""
2650 " field { name: \"foo\" number: 1 label:LABEL_OPTIONAL type:TYPE_INT32 }"
2651 " field { name: \"bar\" number: 1 label:LABEL_OPTIONAL type:TYPE_INT32 }"
2652 "}",
2653
2654 "foo.proto: Foo.bar: NUMBER: Field number 1 has already been used in "
2655 "\"Foo\" by field \"foo\".\n");
2656}
2657
2658TEST_F(ValidationErrorTest, BadMessageSetExtensionType) {
2659 BuildFileWithErrors(
2660 "name: \"foo.proto\" "
2661 "message_type {"
2662 " name: \"MessageSet\""
2663 " options { message_set_wire_format: true }"
2664 " extension_range { start: 4 end: 5 }"
2665 "}"
2666 "message_type {"
2667 " name: \"Foo\""
2668 " extension { name:\"foo\" number:4 label:LABEL_OPTIONAL type:TYPE_INT32"
2669 " extendee: \"MessageSet\" }"
2670 "}",
2671
2672 "foo.proto: Foo.foo: TYPE: Extensions of MessageSets must be optional "
2673 "messages.\n");
2674}
2675
2676TEST_F(ValidationErrorTest, BadMessageSetExtensionLabel) {
2677 BuildFileWithErrors(
2678 "name: \"foo.proto\" "
2679 "message_type {"
2680 " name: \"MessageSet\""
2681 " options { message_set_wire_format: true }"
2682 " extension_range { start: 4 end: 5 }"
2683 "}"
2684 "message_type {"
2685 " name: \"Foo\""
2686 " extension { name:\"foo\" number:4 label:LABEL_REPEATED type:TYPE_MESSAGE"
2687 " type_name: \"Foo\" extendee: \"MessageSet\" }"
2688 "}",
2689
2690 "foo.proto: Foo.foo: TYPE: Extensions of MessageSets must be optional "
2691 "messages.\n");
2692}
2693
2694TEST_F(ValidationErrorTest, FieldInMessageSet) {
2695 BuildFileWithErrors(
2696 "name: \"foo.proto\" "
2697 "message_type {"
2698 " name: \"Foo\""
2699 " options { message_set_wire_format: true }"
2700 " field { name: \"foo\" number: 1 label:LABEL_OPTIONAL type:TYPE_INT32 }"
2701 "}",
2702
2703 "foo.proto: Foo.foo: NAME: MessageSets cannot have fields, only "
2704 "extensions.\n");
2705}
2706
2707TEST_F(ValidationErrorTest, NegativeExtensionRangeNumber) {
2708 BuildFileWithErrors(
2709 "name: \"foo.proto\" "
2710 "message_type {"
2711 " name: \"Foo\""
2712 " extension_range { start: -10 end: -1 }"
2713 "}",
2714
2715 "foo.proto: Foo: NUMBER: Extension numbers must be positive integers.\n");
2716}
2717
2718TEST_F(ValidationErrorTest, HugeExtensionRangeNumber) {
2719 BuildFileWithErrors(
2720 "name: \"foo.proto\" "
2721 "message_type {"
2722 " name: \"Foo\""
2723 " extension_range { start: 1 end: 0x70000000 }"
2724 "}",
2725
2726 "foo.proto: Foo: NUMBER: Extension numbers cannot be greater than "
2727 "536870911.\n");
2728}
2729
2730TEST_F(ValidationErrorTest, ExtensionRangeEndBeforeStart) {
2731 BuildFileWithErrors(
2732 "name: \"foo.proto\" "
2733 "message_type {"
2734 " name: \"Foo\""
2735 " extension_range { start: 10 end: 10 }"
2736 " extension_range { start: 10 end: 5 }"
2737 "}",
2738
2739 "foo.proto: Foo: NUMBER: Extension range end number must be greater than "
2740 "start number.\n"
2741 "foo.proto: Foo: NUMBER: Extension range end number must be greater than "
2742 "start number.\n");
2743}
2744
2745TEST_F(ValidationErrorTest, EmptyEnum) {
2746 BuildFileWithErrors(
2747 "name: \"foo.proto\" "
2748 "enum_type { name: \"Foo\" }"
2749 // Also use the empty enum in a message to make sure there are no crashes
2750 // during validation (possible if the code attempts to derive a default
2751 // value for the field).
2752 "message_type {"
2753 " name: \"Bar\""
2754 " field { name: \"foo\" number: 1 label:LABEL_OPTIONAL type_name:\"Foo\" }"
2755 " field { name: \"bar\" number: 2 label:LABEL_OPTIONAL type_name:\"Foo\" "
2756 " default_value: \"NO_SUCH_VALUE\" }"
2757 "}",
2758
2759 "foo.proto: Foo: NAME: Enums must contain at least one value.\n"
2760 "foo.proto: Bar.bar: DEFAULT_VALUE: Enum type \"Foo\" has no value named "
2761 "\"NO_SUCH_VALUE\".\n");
2762}
2763
2764TEST_F(ValidationErrorTest, UndefinedExtendee) {
2765 BuildFileWithErrors(
2766 "name: \"foo.proto\" "
2767 "message_type {"
2768 " name: \"Foo\""
2769 " extension { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_INT32"
2770 " extendee: \"Bar\" }"
2771 "}",
2772
2773 "foo.proto: Foo.foo: EXTENDEE: \"Bar\" is not defined.\n");
2774}
2775
2776TEST_F(ValidationErrorTest, NonMessageExtendee) {
2777 BuildFileWithErrors(
2778 "name: \"foo.proto\" "
2779 "enum_type { name: \"Bar\" value { name:\"DUMMY\" number:0 } }"
2780 "message_type {"
2781 " name: \"Foo\""
2782 " extension { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_INT32"
2783 " extendee: \"Bar\" }"
2784 "}",
2785
2786 "foo.proto: Foo.foo: EXTENDEE: \"Bar\" is not a message type.\n");
2787}
2788
2789TEST_F(ValidationErrorTest, NotAnExtensionNumber) {
2790 BuildFileWithErrors(
2791 "name: \"foo.proto\" "
2792 "message_type {"
2793 " name: \"Bar\""
2794 "}"
2795 "message_type {"
2796 " name: \"Foo\""
2797 " extension { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_INT32"
2798 " extendee: \"Bar\" }"
2799 "}",
2800
2801 "foo.proto: Foo.foo: NUMBER: \"Bar\" does not declare 1 as an extension "
2802 "number.\n");
2803}
2804
2805TEST_F(ValidationErrorTest, UndefinedFieldType) {
2806 BuildFileWithErrors(
2807 "name: \"foo.proto\" "
2808 "message_type {"
2809 " name: \"Foo\""
2810 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
2811 "}",
2812
2813 "foo.proto: Foo.foo: TYPE: \"Bar\" is not defined.\n");
2814}
2815
2816TEST_F(ValidationErrorTest, FieldTypeDefinedInUndeclaredDependency) {
2817 BuildFile(
2818 "name: \"bar.proto\" "
2819 "message_type { name: \"Bar\" } ");
2820
2821 BuildFileWithErrors(
2822 "name: \"foo.proto\" "
2823 "message_type {"
2824 " name: \"Foo\""
2825 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
2826 "}",
2827 "foo.proto: Foo.foo: TYPE: \"Bar\" seems to be defined in \"bar.proto\", "
2828 "which is not imported by \"foo.proto\". To use it here, please add the "
2829 "necessary import.\n");
2830}
2831
2832TEST_F(ValidationErrorTest, SearchMostLocalFirst) {
2833 // The following should produce an error that Bar.Baz is not defined:
2834 // message Bar { message Baz {} }
2835 // message Foo {
2836 // message Bar {
2837 // // Placing "message Baz{}" here, or removing Foo.Bar altogether,
2838 // // would fix the error.
2839 // }
2840 // optional Bar.Baz baz = 1;
2841 // }
2842 // An one point the lookup code incorrectly did not produce an error in this
2843 // case, because when looking for Bar.Baz, it would try "Foo.Bar.Baz" first,
2844 // fail, and ten try "Bar.Baz" and succeed, even though "Bar" should actually
2845 // refer to the inner Bar, not the outer one.
2846 BuildFileWithErrors(
2847 "name: \"foo.proto\" "
2848 "message_type {"
2849 " name: \"Bar\""
2850 " nested_type { name: \"Baz\" }"
2851 "}"
2852 "message_type {"
2853 " name: \"Foo\""
2854 " nested_type { name: \"Bar\" }"
2855 " field { name:\"baz\" number:1 label:LABEL_OPTIONAL"
2856 " type_name:\"Bar.Baz\" }"
2857 "}",
2858
2859 "foo.proto: Foo.baz: TYPE: \"Bar.Baz\" is not defined.\n");
2860}
2861
kenton@google.comd37d46d2009-04-25 02:53:47 +00002862TEST_F(ValidationErrorTest, SearchMostLocalFirst2) {
2863 // This test would find the most local "Bar" first, and does, but
2864 // proceeds to find the outer one because the inner one's not an
2865 // aggregate.
2866 BuildFile(
2867 "name: \"foo.proto\" "
2868 "message_type {"
2869 " name: \"Bar\""
2870 " nested_type { name: \"Baz\" }"
2871 "}"
2872 "message_type {"
2873 " name: \"Foo\""
2874 " field { name: \"Bar\" number:1 type:TYPE_BYTES } "
2875 " field { name:\"baz\" number:2 label:LABEL_OPTIONAL"
2876 " type_name:\"Bar.Baz\" }"
2877 "}");
2878}
2879
temporal40ee5512008-07-10 02:12:20 +00002880TEST_F(ValidationErrorTest, PackageOriginallyDeclaredInTransitiveDependent) {
2881 // Imagine we have the following:
2882 //
2883 // foo.proto:
2884 // package foo.bar;
2885 // bar.proto:
2886 // package foo.bar;
2887 // import "foo.proto";
2888 // message Bar {}
2889 // baz.proto:
2890 // package foo;
2891 // import "bar.proto"
2892 // message Baz { optional bar.Bar qux = 1; }
2893 //
2894 // When validating baz.proto, we will look up "bar.Bar". As part of this
2895 // lookup, we first lookup "bar" then try to find "Bar" within it. "bar"
2896 // should resolve to "foo.bar". Note, though, that "foo.bar" was originally
2897 // defined in foo.proto, which is not a direct dependency of baz.proto. The
2898 // implementation of FindSymbol() normally only returns symbols in direct
2899 // dependencies, not indirect ones. This test insures that this does not
2900 // prevent it from finding "foo.bar".
2901
2902 BuildFile(
2903 "name: \"foo.proto\" "
2904 "package: \"foo.bar\" ");
2905 BuildFile(
2906 "name: \"bar.proto\" "
2907 "package: \"foo.bar\" "
2908 "dependency: \"foo.proto\" "
2909 "message_type { name: \"Bar\" }");
2910 BuildFile(
2911 "name: \"baz.proto\" "
2912 "package: \"foo\" "
2913 "dependency: \"bar.proto\" "
2914 "message_type { "
2915 " name: \"Baz\" "
2916 " field { name:\"qux\" number:1 label:LABEL_OPTIONAL "
2917 " type_name:\"bar.Bar\" }"
2918 "}");
2919}
2920
2921TEST_F(ValidationErrorTest, FieldTypeNotAType) {
2922 BuildFileWithErrors(
2923 "name: \"foo.proto\" "
2924 "message_type {"
2925 " name: \"Foo\""
kenton@google.comd37d46d2009-04-25 02:53:47 +00002926 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL "
2927 " type_name:\".Foo.bar\" }"
temporal40ee5512008-07-10 02:12:20 +00002928 " field { name:\"bar\" number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }"
2929 "}",
2930
kenton@google.comd37d46d2009-04-25 02:53:47 +00002931 "foo.proto: Foo.foo: TYPE: \".Foo.bar\" is not a type.\n");
2932}
2933
2934TEST_F(ValidationErrorTest, RelativeFieldTypeNotAType) {
2935 BuildFileWithErrors(
2936 "name: \"foo.proto\" "
2937 "message_type {"
2938 " nested_type {"
2939 " name: \"Bar\""
2940 " field { name:\"Baz\" number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }"
2941 " }"
2942 " name: \"Foo\""
2943 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL "
2944 " type_name:\"Bar.Baz\" }"
2945 "}",
2946 "foo.proto: Foo.foo: TYPE: \"Bar.Baz\" is not a type.\n");
2947}
2948
2949TEST_F(ValidationErrorTest, FieldTypeMayBeItsName) {
2950 BuildFile(
2951 "name: \"foo.proto\" "
2952 "message_type {"
2953 " name: \"Bar\""
2954 "}"
2955 "message_type {"
2956 " name: \"Foo\""
2957 " field { name:\"Bar\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
2958 "}");
temporal40ee5512008-07-10 02:12:20 +00002959}
2960
2961TEST_F(ValidationErrorTest, EnumFieldTypeIsMessage) {
2962 BuildFileWithErrors(
2963 "name: \"foo.proto\" "
2964 "message_type { name: \"Bar\" } "
2965 "message_type {"
2966 " name: \"Foo\""
2967 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_ENUM"
2968 " type_name:\"Bar\" }"
2969 "}",
2970
2971 "foo.proto: Foo.foo: TYPE: \"Bar\" is not an enum type.\n");
2972}
2973
2974TEST_F(ValidationErrorTest, MessageFieldTypeIsEnum) {
2975 BuildFileWithErrors(
2976 "name: \"foo.proto\" "
2977 "enum_type { name: \"Bar\" value { name:\"DUMMY\" number:0 } } "
2978 "message_type {"
2979 " name: \"Foo\""
2980 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_MESSAGE"
2981 " type_name:\"Bar\" }"
2982 "}",
2983
2984 "foo.proto: Foo.foo: TYPE: \"Bar\" is not a message type.\n");
2985}
2986
2987TEST_F(ValidationErrorTest, BadEnumDefaultValue) {
2988 BuildFileWithErrors(
2989 "name: \"foo.proto\" "
2990 "enum_type { name: \"Bar\" value { name:\"DUMMY\" number:0 } } "
2991 "message_type {"
2992 " name: \"Foo\""
2993 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\""
2994 " default_value:\"NO_SUCH_VALUE\" }"
2995 "}",
2996
2997 "foo.proto: Foo.foo: DEFAULT_VALUE: Enum type \"Bar\" has no value named "
2998 "\"NO_SUCH_VALUE\".\n");
2999}
3000
3001TEST_F(ValidationErrorTest, PrimitiveWithTypeName) {
3002 BuildFileWithErrors(
3003 "name: \"foo.proto\" "
3004 "message_type {"
3005 " name: \"Foo\""
3006 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_INT32"
3007 " type_name:\"Foo\" }"
3008 "}",
3009
3010 "foo.proto: Foo.foo: TYPE: Field with primitive type has type_name.\n");
3011}
3012
3013TEST_F(ValidationErrorTest, NonPrimitiveWithoutTypeName) {
3014 BuildFileWithErrors(
3015 "name: \"foo.proto\" "
3016 "message_type {"
3017 " name: \"Foo\""
3018 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_MESSAGE }"
3019 "}",
3020
3021 "foo.proto: Foo.foo: TYPE: Field with message or enum type missing "
3022 "type_name.\n");
3023}
3024
3025TEST_F(ValidationErrorTest, InputTypeNotDefined) {
3026 BuildFileWithErrors(
3027 "name: \"foo.proto\" "
3028 "message_type { name: \"Foo\" } "
3029 "service {"
3030 " name: \"TestService\""
3031 " method { name: \"A\" input_type: \"Bar\" output_type: \"Foo\" }"
3032 "}",
3033
3034 "foo.proto: TestService.A: INPUT_TYPE: \"Bar\" is not defined.\n");
3035}
3036
3037TEST_F(ValidationErrorTest, InputTypeNotAMessage) {
3038 BuildFileWithErrors(
3039 "name: \"foo.proto\" "
3040 "message_type { name: \"Foo\" } "
3041 "enum_type { name: \"Bar\" value { name:\"DUMMY\" number:0 } } "
3042 "service {"
3043 " name: \"TestService\""
3044 " method { name: \"A\" input_type: \"Bar\" output_type: \"Foo\" }"
3045 "}",
3046
3047 "foo.proto: TestService.A: INPUT_TYPE: \"Bar\" is not a message type.\n");
3048}
3049
3050TEST_F(ValidationErrorTest, OutputTypeNotDefined) {
3051 BuildFileWithErrors(
3052 "name: \"foo.proto\" "
3053 "message_type { name: \"Foo\" } "
3054 "service {"
3055 " name: \"TestService\""
3056 " method { name: \"A\" input_type: \"Foo\" output_type: \"Bar\" }"
3057 "}",
3058
3059 "foo.proto: TestService.A: OUTPUT_TYPE: \"Bar\" is not defined.\n");
3060}
3061
3062TEST_F(ValidationErrorTest, OutputTypeNotAMessage) {
3063 BuildFileWithErrors(
3064 "name: \"foo.proto\" "
3065 "message_type { name: \"Foo\" } "
3066 "enum_type { name: \"Bar\" value { name:\"DUMMY\" number:0 } } "
3067 "service {"
3068 " name: \"TestService\""
3069 " method { name: \"A\" input_type: \"Foo\" output_type: \"Bar\" }"
3070 "}",
3071
3072 "foo.proto: TestService.A: OUTPUT_TYPE: \"Bar\" is not a message type.\n");
3073}
3074
kenton@google.com2d6daa72009-01-22 01:27:00 +00003075TEST_F(ValidationErrorTest, IllegalPackedField) {
3076 BuildFileWithErrors(
3077 "name: \"foo.proto\" "
3078 "message_type {\n"
3079 " name: \"Foo\""
3080 " field { name:\"packed_string\" number:1 label:LABEL_REPEATED "
3081 " type:TYPE_STRING "
3082 " options { uninterpreted_option {"
3083 " name { name_part: \"packed\" is_extension: false }"
3084 " identifier_value: \"true\" }}}\n"
3085 " field { name:\"packed_message\" number:3 label:LABEL_REPEATED "
3086 " type_name: \"Foo\""
3087 " options { uninterpreted_option {"
3088 " name { name_part: \"packed\" is_extension: false }"
3089 " identifier_value: \"true\" }}}\n"
3090 " field { name:\"optional_int32\" number: 4 label: LABEL_OPTIONAL "
3091 " type:TYPE_INT32 "
3092 " options { uninterpreted_option {"
3093 " name { name_part: \"packed\" is_extension: false }"
3094 " identifier_value: \"true\" }}}\n"
3095 "}",
3096
3097 "foo.proto: Foo.packed_string: TYPE: [packed = true] can only be "
3098 "specified for repeated primitive fields.\n"
3099 "foo.proto: Foo.packed_message: TYPE: [packed = true] can only be "
3100 "specified for repeated primitive fields.\n"
3101 "foo.proto: Foo.optional_int32: TYPE: [packed = true] can only be "
3102 "specified for repeated primitive fields.\n"
3103 );
3104}
kenton@google.com24bf56f2008-09-24 20:31:01 +00003105
3106TEST_F(ValidationErrorTest, OptionWrongType) {
3107 BuildFileWithErrors(
3108 "name: \"foo.proto\" "
3109 "message_type { "
3110 " name: \"TestMessage\" "
3111 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_STRING "
3112 " options { uninterpreted_option { name { name_part: \"ctype\" "
3113 " is_extension: false }"
3114 " positive_int_value: 1 }"
3115 " }"
3116 " }"
3117 "}\n",
3118
3119 "foo.proto: TestMessage.foo: OPTION_VALUE: Value must be identifier for "
3120 "enum-valued option \"google.protobuf.FieldOptions.ctype\".\n");
3121}
3122
3123TEST_F(ValidationErrorTest, OptionExtendsAtomicType) {
3124 BuildFileWithErrors(
3125 "name: \"foo.proto\" "
3126 "message_type { "
3127 " name: \"TestMessage\" "
3128 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_STRING "
3129 " options { uninterpreted_option { name { name_part: \"ctype\" "
3130 " is_extension: false }"
3131 " name { name_part: \"foo\" "
3132 " is_extension: true }"
3133 " positive_int_value: 1 }"
3134 " }"
3135 " }"
3136 "}\n",
3137
3138 "foo.proto: TestMessage.foo: OPTION_NAME: Option \"ctype\" is an "
3139 "atomic type, not a message.\n");
3140}
3141
3142TEST_F(ValidationErrorTest, DupOption) {
3143 BuildFileWithErrors(
3144 "name: \"foo.proto\" "
3145 "message_type { "
3146 " name: \"TestMessage\" "
3147 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_UINT32 "
3148 " options { uninterpreted_option { name { name_part: \"ctype\" "
3149 " is_extension: false }"
3150 " identifier_value: \"CORD\" }"
3151 " uninterpreted_option { name { name_part: \"ctype\" "
3152 " is_extension: false }"
3153 " identifier_value: \"CORD\" }"
3154 " }"
3155 " }"
3156 "}\n",
3157
3158 "foo.proto: TestMessage.foo: OPTION_NAME: Option \"ctype\" was "
3159 "already set.\n");
3160}
3161
3162TEST_F(ValidationErrorTest, InvalidOptionName) {
3163 BuildFileWithErrors(
3164 "name: \"foo.proto\" "
3165 "message_type { "
3166 " name: \"TestMessage\" "
3167 " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_BOOL "
3168 " options { uninterpreted_option { "
3169 " name { name_part: \"uninterpreted_option\" "
3170 " is_extension: false }"
3171 " positive_int_value: 1 "
3172 " }"
3173 " }"
3174 " }"
3175 "}\n",
3176
3177 "foo.proto: TestMessage.foo: OPTION_NAME: Option must not use "
3178 "reserved name \"uninterpreted_option\".\n");
3179}
3180
3181TEST_F(ValidationErrorTest, RepeatedOption) {
3182 BuildDescriptorMessagesInTestPool();
3183
3184 BuildFileWithErrors(
3185 "name: \"foo.proto\" "
3186 "dependency: \"google/protobuf/descriptor.proto\" "
3187 "extension { name: \"foo\" number: 7672757 label: LABEL_REPEATED "
3188 " type: TYPE_FLOAT extendee: \"google.protobuf.FileOptions\" }"
3189 "options { uninterpreted_option { name { name_part: \"foo\" "
3190 " is_extension: true } "
3191 " double_value: 1.2 } }",
3192
3193 "foo.proto: foo.proto: OPTION_NAME: Option field \"(foo)\" is repeated. "
3194 "Repeated options are not supported.\n");
3195}
3196
3197TEST_F(ValidationErrorTest, CustomOptionConflictingFieldNumber) {
3198 BuildDescriptorMessagesInTestPool();
3199
3200 BuildFileWithErrors(
3201 "name: \"foo.proto\" "
3202 "dependency: \"google/protobuf/descriptor.proto\" "
3203 "extension { name: \"foo1\" number: 7672757 label: LABEL_OPTIONAL "
3204 " type: TYPE_INT32 extendee: \"google.protobuf.FieldOptions\" }"
3205 "extension { name: \"foo2\" number: 7672757 label: LABEL_OPTIONAL "
3206 " type: TYPE_INT32 extendee: \"google.protobuf.FieldOptions\" }",
3207
3208 "foo.proto: foo2: NUMBER: Extension number 7672757 has already been used "
3209 "in \"google.protobuf.FieldOptions\" by extension \"foo1\".\n");
3210}
3211
3212TEST_F(ValidationErrorTest, Int32OptionValueOutOfPositiveRange) {
3213 BuildDescriptorMessagesInTestPool();
3214
3215 BuildFileWithErrors(
3216 "name: \"foo.proto\" "
3217 "dependency: \"google/protobuf/descriptor.proto\" "
3218 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
3219 " type: TYPE_INT32 extendee: \"google.protobuf.FileOptions\" }"
3220 "options { uninterpreted_option { name { name_part: \"foo\" "
3221 " is_extension: true } "
3222 " positive_int_value: 0x80000000 } "
3223 "}",
3224
3225 "foo.proto: foo.proto: OPTION_VALUE: Value out of range "
3226 "for int32 option \"foo\".\n");
3227}
3228
3229TEST_F(ValidationErrorTest, Int32OptionValueOutOfNegativeRange) {
3230 BuildDescriptorMessagesInTestPool();
3231
3232 BuildFileWithErrors(
3233 "name: \"foo.proto\" "
3234 "dependency: \"google/protobuf/descriptor.proto\" "
3235 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
3236 " type: TYPE_INT32 extendee: \"google.protobuf.FileOptions\" }"
3237 "options { uninterpreted_option { name { name_part: \"foo\" "
3238 " is_extension: true } "
3239 " negative_int_value: -0x80000001 } "
3240 "}",
3241
3242 "foo.proto: foo.proto: OPTION_VALUE: Value out of range "
3243 "for int32 option \"foo\".\n");
3244}
3245
3246TEST_F(ValidationErrorTest, Int32OptionValueIsNotPositiveInt) {
3247 BuildDescriptorMessagesInTestPool();
3248
3249 BuildFileWithErrors(
3250 "name: \"foo.proto\" "
3251 "dependency: \"google/protobuf/descriptor.proto\" "
3252 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
3253 " type: TYPE_INT32 extendee: \"google.protobuf.FileOptions\" }"
3254 "options { uninterpreted_option { name { name_part: \"foo\" "
3255 " is_extension: true } "
3256 " string_value: \"5\" } }",
3257
3258 "foo.proto: foo.proto: OPTION_VALUE: Value must be integer "
3259 "for int32 option \"foo\".\n");
3260}
3261
3262TEST_F(ValidationErrorTest, Int64OptionValueOutOfRange) {
3263 BuildDescriptorMessagesInTestPool();
3264
3265 BuildFileWithErrors(
3266 "name: \"foo.proto\" "
3267 "dependency: \"google/protobuf/descriptor.proto\" "
3268 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
3269 " type: TYPE_INT64 extendee: \"google.protobuf.FileOptions\" }"
3270 "options { uninterpreted_option { name { name_part: \"foo\" "
3271 " is_extension: true } "
3272 " positive_int_value: 0x8000000000000000 } "
3273 "}",
3274
3275 "foo.proto: foo.proto: OPTION_VALUE: Value out of range "
3276 "for int64 option \"foo\".\n");
3277}
3278
3279TEST_F(ValidationErrorTest, Int64OptionValueIsNotPositiveInt) {
3280 BuildDescriptorMessagesInTestPool();
3281
3282 BuildFileWithErrors(
3283 "name: \"foo.proto\" "
3284 "dependency: \"google/protobuf/descriptor.proto\" "
3285 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
3286 " type: TYPE_INT64 extendee: \"google.protobuf.FileOptions\" }"
3287 "options { uninterpreted_option { name { name_part: \"foo\" "
3288 " is_extension: true } "
3289 " identifier_value: \"5\" } }",
3290
3291 "foo.proto: foo.proto: OPTION_VALUE: Value must be integer "
3292 "for int64 option \"foo\".\n");
3293}
3294
3295TEST_F(ValidationErrorTest, UInt32OptionValueOutOfRange) {
3296 BuildDescriptorMessagesInTestPool();
3297
3298 BuildFileWithErrors(
3299 "name: \"foo.proto\" "
3300 "dependency: \"google/protobuf/descriptor.proto\" "
3301 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
3302 " type: TYPE_UINT32 extendee: \"google.protobuf.FileOptions\" }"
3303 "options { uninterpreted_option { name { name_part: \"foo\" "
3304 " is_extension: true } "
3305 " positive_int_value: 0x100000000 } }",
3306
3307 "foo.proto: foo.proto: OPTION_VALUE: Value out of range "
3308 "for uint32 option \"foo\".\n");
3309}
3310
3311TEST_F(ValidationErrorTest, UInt32OptionValueIsNotPositiveInt) {
3312 BuildDescriptorMessagesInTestPool();
3313
3314 BuildFileWithErrors(
3315 "name: \"foo.proto\" "
3316 "dependency: \"google/protobuf/descriptor.proto\" "
3317 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
3318 " type: TYPE_UINT32 extendee: \"google.protobuf.FileOptions\" }"
3319 "options { uninterpreted_option { name { name_part: \"foo\" "
3320 " is_extension: true } "
3321 " double_value: -5.6 } }",
3322
3323 "foo.proto: foo.proto: OPTION_VALUE: Value must be non-negative integer "
3324 "for uint32 option \"foo\".\n");
3325}
3326
3327TEST_F(ValidationErrorTest, UInt64OptionValueIsNotPositiveInt) {
3328 BuildDescriptorMessagesInTestPool();
3329
3330 BuildFileWithErrors(
3331 "name: \"foo.proto\" "
3332 "dependency: \"google/protobuf/descriptor.proto\" "
3333 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
3334 " type: TYPE_UINT64 extendee: \"google.protobuf.FileOptions\" }"
3335 "options { uninterpreted_option { name { name_part: \"foo\" "
3336 " is_extension: true } "
3337 " negative_int_value: -5 } }",
3338
3339 "foo.proto: foo.proto: OPTION_VALUE: Value must be non-negative integer "
3340 "for uint64 option \"foo\".\n");
3341}
3342
3343TEST_F(ValidationErrorTest, FloatOptionValueIsNotNumber) {
3344 BuildDescriptorMessagesInTestPool();
3345
3346 BuildFileWithErrors(
3347 "name: \"foo.proto\" "
3348 "dependency: \"google/protobuf/descriptor.proto\" "
3349 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
3350 " type: TYPE_FLOAT extendee: \"google.protobuf.FileOptions\" }"
3351 "options { uninterpreted_option { name { name_part: \"foo\" "
3352 " is_extension: true } "
3353 " string_value: \"bar\" } }",
3354
3355 "foo.proto: foo.proto: OPTION_VALUE: Value must be number "
3356 "for float option \"foo\".\n");
3357}
3358
3359TEST_F(ValidationErrorTest, DoubleOptionValueIsNotNumber) {
3360 BuildDescriptorMessagesInTestPool();
3361
3362 BuildFileWithErrors(
3363 "name: \"foo.proto\" "
3364 "dependency: \"google/protobuf/descriptor.proto\" "
3365 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
3366 " type: TYPE_DOUBLE extendee: \"google.protobuf.FileOptions\" }"
3367 "options { uninterpreted_option { name { name_part: \"foo\" "
3368 " is_extension: true } "
3369 " string_value: \"bar\" } }",
3370
3371 "foo.proto: foo.proto: OPTION_VALUE: Value must be number "
3372 "for double option \"foo\".\n");
3373}
3374
3375TEST_F(ValidationErrorTest, BoolOptionValueIsNotTrueOrFalse) {
3376 BuildDescriptorMessagesInTestPool();
3377
3378 BuildFileWithErrors(
3379 "name: \"foo.proto\" "
3380 "dependency: \"google/protobuf/descriptor.proto\" "
3381 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
3382 " type: TYPE_BOOL extendee: \"google.protobuf.FileOptions\" }"
3383 "options { uninterpreted_option { name { name_part: \"foo\" "
3384 " is_extension: true } "
3385 " identifier_value: \"bar\" } }",
3386
3387 "foo.proto: foo.proto: OPTION_VALUE: Value must be \"true\" or \"false\" "
3388 "for boolean option \"foo\".\n");
3389}
3390
3391TEST_F(ValidationErrorTest, EnumOptionValueIsNotIdentifier) {
3392 BuildDescriptorMessagesInTestPool();
3393
3394 BuildFileWithErrors(
3395 "name: \"foo.proto\" "
3396 "dependency: \"google/protobuf/descriptor.proto\" "
3397 "enum_type { name: \"FooEnum\" value { name: \"BAR\" number: 1 } "
3398 " value { name: \"BAZ\" number: 2 } }"
3399 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
3400 " type: TYPE_ENUM type_name: \"FooEnum\" "
3401 " extendee: \"google.protobuf.FileOptions\" }"
3402 "options { uninterpreted_option { name { name_part: \"foo\" "
3403 " is_extension: true } "
3404 " string_value: \"QUUX\" } }",
3405
3406 "foo.proto: foo.proto: OPTION_VALUE: Value must be identifier for "
3407 "enum-valued option \"foo\".\n");
3408}
3409
3410TEST_F(ValidationErrorTest, EnumOptionValueIsNotEnumValueName) {
3411 BuildDescriptorMessagesInTestPool();
3412
3413 BuildFileWithErrors(
3414 "name: \"foo.proto\" "
3415 "dependency: \"google/protobuf/descriptor.proto\" "
3416 "enum_type { name: \"FooEnum\" value { name: \"BAR\" number: 1 } "
3417 " value { name: \"BAZ\" number: 2 } }"
3418 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
3419 " type: TYPE_ENUM type_name: \"FooEnum\" "
3420 " extendee: \"google.protobuf.FileOptions\" }"
3421 "options { uninterpreted_option { name { name_part: \"foo\" "
3422 " is_extension: true } "
3423 " identifier_value: \"QUUX\" } }",
3424
3425 "foo.proto: foo.proto: OPTION_VALUE: Enum type \"FooEnum\" has no value "
3426 "named \"QUUX\" for option \"foo\".\n");
3427}
3428
3429TEST_F(ValidationErrorTest, EnumOptionValueIsSiblingEnumValueName) {
3430 BuildDescriptorMessagesInTestPool();
3431
3432 BuildFileWithErrors(
3433 "name: \"foo.proto\" "
3434 "dependency: \"google/protobuf/descriptor.proto\" "
3435 "enum_type { name: \"FooEnum1\" value { name: \"BAR\" number: 1 } "
3436 " value { name: \"BAZ\" number: 2 } }"
3437 "enum_type { name: \"FooEnum2\" value { name: \"QUX\" number: 1 } "
3438 " value { name: \"QUUX\" number: 2 } }"
3439 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
3440 " type: TYPE_ENUM type_name: \"FooEnum1\" "
3441 " extendee: \"google.protobuf.FileOptions\" }"
3442 "options { uninterpreted_option { name { name_part: \"foo\" "
3443 " is_extension: true } "
3444 " identifier_value: \"QUUX\" } }",
3445
3446 "foo.proto: foo.proto: OPTION_VALUE: Enum type \"FooEnum1\" has no value "
3447 "named \"QUUX\" for option \"foo\". This appears to be a value from a "
3448 "sibling type.\n");
3449}
3450
3451TEST_F(ValidationErrorTest, StringOptionValueIsNotString) {
3452 BuildDescriptorMessagesInTestPool();
3453
3454 BuildFileWithErrors(
3455 "name: \"foo.proto\" "
3456 "dependency: \"google/protobuf/descriptor.proto\" "
3457 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
3458 " type: TYPE_STRING extendee: \"google.protobuf.FileOptions\" }"
3459 "options { uninterpreted_option { name { name_part: \"foo\" "
3460 " is_extension: true } "
3461 " identifier_value: \"QUUX\" } }",
3462
3463 "foo.proto: foo.proto: OPTION_VALUE: Value must be quoted string for "
3464 "string option \"foo\".\n");
3465}
3466
liujisi@google.com33165fe2010-11-02 13:14:58 +00003467// Helper function for tests that check for aggregate value parsing
3468// errors. The "value" argument is embedded inside the
3469// "uninterpreted_option" portion of the result.
3470static string EmbedAggregateValue(const char* value) {
3471 return strings::Substitute(
3472 "name: \"foo.proto\" "
3473 "dependency: \"google/protobuf/descriptor.proto\" "
3474 "message_type { name: \"Foo\" } "
3475 "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
3476 " type: TYPE_MESSAGE type_name: \"Foo\" "
3477 " extendee: \"google.protobuf.FileOptions\" }"
3478 "options { uninterpreted_option { name { name_part: \"foo\" "
3479 " is_extension: true } "
3480 " $0 } }",
3481 value);
3482}
3483
3484TEST_F(ValidationErrorTest, AggregateValueNotFound) {
kenton@google.com24bf56f2008-09-24 20:31:01 +00003485 BuildDescriptorMessagesInTestPool();
3486
3487 BuildFileWithErrors(
liujisi@google.com33165fe2010-11-02 13:14:58 +00003488 EmbedAggregateValue("string_value: \"\""),
3489 "foo.proto: foo.proto: OPTION_VALUE: Option \"foo\" is a message. "
3490 "To set the entire message, use syntax like "
3491 "\"foo = { <proto text format> }\". To set fields within it, use "
3492 "syntax like \"foo.foo = value\".\n");
3493}
kenton@google.com24bf56f2008-09-24 20:31:01 +00003494
liujisi@google.com33165fe2010-11-02 13:14:58 +00003495TEST_F(ValidationErrorTest, AggregateValueParseError) {
3496 BuildDescriptorMessagesInTestPool();
3497
3498 BuildFileWithErrors(
3499 EmbedAggregateValue("aggregate_value: \"1+2\""),
3500 "foo.proto: foo.proto: OPTION_VALUE: Error while parsing option "
3501 "value for \"foo\": Expected identifier.\n");
3502}
3503
3504TEST_F(ValidationErrorTest, AggregateValueUnknownFields) {
3505 BuildDescriptorMessagesInTestPool();
3506
3507 BuildFileWithErrors(
3508 EmbedAggregateValue("aggregate_value: \"x:100\""),
3509 "foo.proto: foo.proto: OPTION_VALUE: Error while parsing option "
3510 "value for \"foo\": Message type \"Foo\" has no field named \"x\".\n");
kenton@google.com24bf56f2008-09-24 20:31:01 +00003511}
3512
kenton@google.com80b1d622009-07-29 01:13:20 +00003513TEST_F(ValidationErrorTest, NotLiteImportsLite) {
3514 BuildFile(
3515 "name: \"bar.proto\" "
3516 "options { optimize_for: LITE_RUNTIME } ");
3517
3518 BuildFileWithErrors(
3519 "name: \"foo.proto\" "
3520 "dependency: \"bar.proto\" ",
3521
3522 "foo.proto: foo.proto: OTHER: Files that do not use optimize_for = "
3523 "LITE_RUNTIME cannot import files which do use this option. This file "
3524 "is not lite, but it imports \"bar.proto\" which is.\n");
3525}
3526
3527TEST_F(ValidationErrorTest, LiteExtendsNotLite) {
3528 BuildFile(
3529 "name: \"bar.proto\" "
3530 "message_type: {"
3531 " name: \"Bar\""
3532 " extension_range { start: 1 end: 1000 }"
3533 "}");
3534
3535 BuildFileWithErrors(
3536 "name: \"foo.proto\" "
3537 "dependency: \"bar.proto\" "
3538 "options { optimize_for: LITE_RUNTIME } "
3539 "extension { name: \"ext\" number: 123 label: LABEL_OPTIONAL "
3540 " type: TYPE_INT32 extendee: \"Bar\" }",
3541
3542 "foo.proto: ext: EXTENDEE: Extensions to non-lite types can only be "
3543 "declared in non-lite files. Note that you cannot extend a non-lite "
3544 "type to contain a lite type, but the reverse is allowed.\n");
3545}
3546
3547TEST_F(ValidationErrorTest, NoLiteServices) {
3548 BuildFileWithErrors(
3549 "name: \"foo.proto\" "
liujisi@google.com33165fe2010-11-02 13:14:58 +00003550 "options {"
3551 " optimize_for: LITE_RUNTIME"
3552 " cc_generic_services: true"
3553 " java_generic_services: true"
3554 "} "
kenton@google.com80b1d622009-07-29 01:13:20 +00003555 "service { name: \"Foo\" }",
3556
3557 "foo.proto: Foo: NAME: Files with optimize_for = LITE_RUNTIME cannot "
kenton@google.comd09ab852010-04-19 19:15:12 +00003558 "define services unless you set both options cc_generic_services and "
3559 "java_generic_sevices to false.\n");
3560
3561 BuildFile(
3562 "name: \"bar.proto\" "
3563 "options {"
3564 " optimize_for: LITE_RUNTIME"
3565 " cc_generic_services: false"
3566 " java_generic_services: false"
3567 "} "
liujisi@google.com33165fe2010-11-02 13:14:58 +00003568 "service { name: \"Bar\" }");
kenton@google.com80b1d622009-07-29 01:13:20 +00003569}
3570
temporal40ee5512008-07-10 02:12:20 +00003571TEST_F(ValidationErrorTest, RollbackAfterError) {
3572 // Build a file which contains every kind of construct but references an
3573 // undefined type. All these constructs will be added to the symbol table
3574 // before the undefined type error is noticed. The DescriptorPool will then
3575 // have to roll everything back.
3576 BuildFileWithErrors(
3577 "name: \"foo.proto\" "
3578 "message_type {"
3579 " name: \"TestMessage\""
3580 " field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 }"
3581 "} "
3582 "enum_type {"
3583 " name: \"TestEnum\""
3584 " value { name:\"BAR\" number:1 }"
3585 "} "
3586 "service {"
3587 " name: \"TestService\""
3588 " method {"
3589 " name: \"Baz\""
3590 " input_type: \"NoSuchType\"" // error
3591 " output_type: \"TestMessage\""
3592 " }"
3593 "}",
3594
3595 "foo.proto: TestService.Baz: INPUT_TYPE: \"NoSuchType\" is not defined.\n");
3596
3597 // Make sure that if we build the same file again with the error fixed,
3598 // it works. If the above rollback was incomplete, then some symbols will
3599 // be left defined, and this second attempt will fail since it tries to
3600 // re-define the same symbols.
3601 BuildFile(
3602 "name: \"foo.proto\" "
3603 "message_type {"
3604 " name: \"TestMessage\""
3605 " field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 }"
3606 "} "
3607 "enum_type {"
3608 " name: \"TestEnum\""
3609 " value { name:\"BAR\" number:1 }"
3610 "} "
3611 "service {"
3612 " name: \"TestService\""
3613 " method { name:\"Baz\""
3614 " input_type:\"TestMessage\""
3615 " output_type:\"TestMessage\" }"
3616 "}");
3617}
3618
3619TEST_F(ValidationErrorTest, ErrorsReportedToLogError) {
3620 // Test that errors are reported to GOOGLE_LOG(ERROR) if no error collector is
3621 // provided.
3622
3623 FileDescriptorProto file_proto;
3624 ASSERT_TRUE(TextFormat::ParseFromString(
3625 "name: \"foo.proto\" "
3626 "message_type { name: \"Foo\" } "
3627 "message_type { name: \"Foo\" } ",
3628 &file_proto));
3629
3630 vector<string> errors;
3631
3632 {
3633 ScopedMemoryLog log;
3634 EXPECT_TRUE(pool_.BuildFile(file_proto) == NULL);
3635 errors = log.GetMessages(ERROR);
3636 }
3637
3638 ASSERT_EQ(2, errors.size());
3639
3640 EXPECT_EQ("Invalid proto descriptor for file \"foo.proto\":", errors[0]);
3641 EXPECT_EQ(" Foo: \"Foo\" is already defined.", errors[1]);
3642}
3643
3644// ===================================================================
3645// DescriptorDatabase
3646
3647static void AddToDatabase(SimpleDescriptorDatabase* database,
3648 const char* file_text) {
3649 FileDescriptorProto file_proto;
3650 EXPECT_TRUE(TextFormat::ParseFromString(file_text, &file_proto));
3651 database->Add(file_proto);
3652}
3653
3654class DatabaseBackedPoolTest : public testing::Test {
3655 protected:
3656 DatabaseBackedPoolTest() {}
3657
3658 SimpleDescriptorDatabase database_;
3659
3660 virtual void SetUp() {
3661 AddToDatabase(&database_,
3662 "name: \"foo.proto\" "
3663 "message_type { name:\"Foo\" extension_range { start: 1 end: 100 } } "
3664 "enum_type { name:\"TestEnum\" value { name:\"DUMMY\" number:0 } } "
3665 "service { name:\"TestService\" } ");
3666 AddToDatabase(&database_,
3667 "name: \"bar.proto\" "
3668 "dependency: \"foo.proto\" "
3669 "message_type { name:\"Bar\" } "
3670 "extension { name:\"foo_ext\" extendee: \".Foo\" number:5 "
3671 " label:LABEL_OPTIONAL type:TYPE_INT32 } ");
3672 }
3673
3674 // We can't inject a file containing errors into a DescriptorPool, so we
3675 // need an actual mock DescriptorDatabase to test errors.
3676 class ErrorDescriptorDatabase : public DescriptorDatabase {
3677 public:
3678 ErrorDescriptorDatabase() {}
3679 ~ErrorDescriptorDatabase() {}
3680
3681 // implements DescriptorDatabase ---------------------------------
3682 bool FindFileByName(const string& filename,
3683 FileDescriptorProto* output) {
3684 // error.proto and error2.proto cyclically import each other.
3685 if (filename == "error.proto") {
3686 output->Clear();
3687 output->set_name("error.proto");
3688 output->add_dependency("error2.proto");
3689 return true;
3690 } else if (filename == "error2.proto") {
3691 output->Clear();
3692 output->set_name("error2.proto");
3693 output->add_dependency("error.proto");
3694 return true;
3695 } else {
3696 return false;
3697 }
3698 }
3699 bool FindFileContainingSymbol(const string& symbol_name,
3700 FileDescriptorProto* output) {
3701 return false;
3702 }
3703 bool FindFileContainingExtension(const string& containing_type,
3704 int field_number,
3705 FileDescriptorProto* output) {
3706 return false;
3707 }
3708 };
3709
3710 // A DescriptorDatabase that counts how many times each method has been
3711 // called and forwards to some other DescriptorDatabase.
3712 class CallCountingDatabase : public DescriptorDatabase {
3713 public:
3714 CallCountingDatabase(DescriptorDatabase* wrapped_db)
3715 : wrapped_db_(wrapped_db) {
3716 Clear();
3717 }
3718 ~CallCountingDatabase() {}
3719
3720 DescriptorDatabase* wrapped_db_;
3721
3722 int call_count_;
3723
3724 void Clear() {
3725 call_count_ = 0;
3726 }
3727
3728 // implements DescriptorDatabase ---------------------------------
3729 bool FindFileByName(const string& filename,
3730 FileDescriptorProto* output) {
3731 ++call_count_;
3732 return wrapped_db_->FindFileByName(filename, output);
3733 }
3734 bool FindFileContainingSymbol(const string& symbol_name,
3735 FileDescriptorProto* output) {
3736 ++call_count_;
3737 return wrapped_db_->FindFileContainingSymbol(symbol_name, output);
3738 }
3739 bool FindFileContainingExtension(const string& containing_type,
3740 int field_number,
3741 FileDescriptorProto* output) {
3742 ++call_count_;
3743 return wrapped_db_->FindFileContainingExtension(
3744 containing_type, field_number, output);
3745 }
3746 };
3747
3748 // A DescriptorDatabase which falsely always returns foo.proto when searching
3749 // for any symbol or extension number. This shouldn't cause the
3750 // DescriptorPool to reload foo.proto if it is already loaded.
3751 class FalsePositiveDatabase : public DescriptorDatabase {
3752 public:
3753 FalsePositiveDatabase(DescriptorDatabase* wrapped_db)
3754 : wrapped_db_(wrapped_db) {}
3755 ~FalsePositiveDatabase() {}
3756
3757 DescriptorDatabase* wrapped_db_;
3758
3759 // implements DescriptorDatabase ---------------------------------
3760 bool FindFileByName(const string& filename,
3761 FileDescriptorProto* output) {
3762 return wrapped_db_->FindFileByName(filename, output);
3763 }
3764 bool FindFileContainingSymbol(const string& symbol_name,
3765 FileDescriptorProto* output) {
3766 return FindFileByName("foo.proto", output);
3767 }
3768 bool FindFileContainingExtension(const string& containing_type,
3769 int field_number,
3770 FileDescriptorProto* output) {
3771 return FindFileByName("foo.proto", output);
3772 }
3773 };
3774};
3775
3776TEST_F(DatabaseBackedPoolTest, FindFileByName) {
3777 DescriptorPool pool(&database_);
3778
3779 const FileDescriptor* foo = pool.FindFileByName("foo.proto");
3780 ASSERT_TRUE(foo != NULL);
3781 EXPECT_EQ("foo.proto", foo->name());
3782 ASSERT_EQ(1, foo->message_type_count());
3783 EXPECT_EQ("Foo", foo->message_type(0)->name());
3784
3785 EXPECT_EQ(foo, pool.FindFileByName("foo.proto"));
3786
3787 EXPECT_TRUE(pool.FindFileByName("no_such_file.proto") == NULL);
3788}
3789
3790TEST_F(DatabaseBackedPoolTest, FindDependencyBeforeDependent) {
3791 DescriptorPool pool(&database_);
3792
3793 const FileDescriptor* foo = pool.FindFileByName("foo.proto");
3794 ASSERT_TRUE(foo != NULL);
3795 EXPECT_EQ("foo.proto", foo->name());
3796 ASSERT_EQ(1, foo->message_type_count());
3797 EXPECT_EQ("Foo", foo->message_type(0)->name());
3798
3799 const FileDescriptor* bar = pool.FindFileByName("bar.proto");
3800 ASSERT_TRUE(bar != NULL);
3801 EXPECT_EQ("bar.proto", bar->name());
3802 ASSERT_EQ(1, bar->message_type_count());
3803 EXPECT_EQ("Bar", bar->message_type(0)->name());
3804
3805 ASSERT_EQ(1, bar->dependency_count());
3806 EXPECT_EQ(foo, bar->dependency(0));
3807}
3808
3809TEST_F(DatabaseBackedPoolTest, FindDependentBeforeDependency) {
3810 DescriptorPool pool(&database_);
3811
3812 const FileDescriptor* bar = pool.FindFileByName("bar.proto");
3813 ASSERT_TRUE(bar != NULL);
3814 EXPECT_EQ("bar.proto", bar->name());
3815 ASSERT_EQ(1, bar->message_type_count());
3816 ASSERT_EQ("Bar", bar->message_type(0)->name());
3817
3818 const FileDescriptor* foo = pool.FindFileByName("foo.proto");
3819 ASSERT_TRUE(foo != NULL);
3820 EXPECT_EQ("foo.proto", foo->name());
3821 ASSERT_EQ(1, foo->message_type_count());
3822 ASSERT_EQ("Foo", foo->message_type(0)->name());
3823
3824 ASSERT_EQ(1, bar->dependency_count());
3825 EXPECT_EQ(foo, bar->dependency(0));
3826}
3827
3828TEST_F(DatabaseBackedPoolTest, FindFileContainingSymbol) {
3829 DescriptorPool pool(&database_);
3830
3831 const FileDescriptor* file = pool.FindFileContainingSymbol("Foo");
3832 ASSERT_TRUE(file != NULL);
3833 EXPECT_EQ("foo.proto", file->name());
3834 EXPECT_EQ(file, pool.FindFileByName("foo.proto"));
3835
3836 EXPECT_TRUE(pool.FindFileContainingSymbol("NoSuchSymbol") == NULL);
3837}
3838
3839TEST_F(DatabaseBackedPoolTest, FindMessageTypeByName) {
3840 DescriptorPool pool(&database_);
3841
3842 const Descriptor* type = pool.FindMessageTypeByName("Foo");
3843 ASSERT_TRUE(type != NULL);
3844 EXPECT_EQ("Foo", type->name());
3845 EXPECT_EQ(type->file(), pool.FindFileByName("foo.proto"));
3846
3847 EXPECT_TRUE(pool.FindMessageTypeByName("NoSuchType") == NULL);
3848}
3849
3850TEST_F(DatabaseBackedPoolTest, FindExtensionByNumber) {
3851 DescriptorPool pool(&database_);
3852
3853 const Descriptor* foo = pool.FindMessageTypeByName("Foo");
3854 ASSERT_TRUE(foo != NULL);
3855
3856 const FieldDescriptor* extension = pool.FindExtensionByNumber(foo, 5);
3857 ASSERT_TRUE(extension != NULL);
3858 EXPECT_EQ("foo_ext", extension->name());
3859 EXPECT_EQ(extension->file(), pool.FindFileByName("bar.proto"));
3860
3861 EXPECT_TRUE(pool.FindExtensionByNumber(foo, 12) == NULL);
3862}
3863
kenton@google.comd37d46d2009-04-25 02:53:47 +00003864TEST_F(DatabaseBackedPoolTest, FindAllExtensions) {
3865 DescriptorPool pool(&database_);
3866
3867 const Descriptor* foo = pool.FindMessageTypeByName("Foo");
3868
3869 for (int i = 0; i < 2; ++i) {
3870 // Repeat the lookup twice, to check that we get consistent
3871 // results despite the fallback database lookup mutating the pool.
3872 vector<const FieldDescriptor*> extensions;
3873 pool.FindAllExtensions(foo, &extensions);
3874 ASSERT_EQ(1, extensions.size());
3875 EXPECT_EQ(5, extensions[0]->number());
3876 }
3877}
3878
temporal40ee5512008-07-10 02:12:20 +00003879TEST_F(DatabaseBackedPoolTest, ErrorWithoutErrorCollector) {
3880 ErrorDescriptorDatabase error_database;
3881 DescriptorPool pool(&error_database);
3882
3883 vector<string> errors;
3884
3885 {
3886 ScopedMemoryLog log;
3887 EXPECT_TRUE(pool.FindFileByName("error.proto") == NULL);
3888 errors = log.GetMessages(ERROR);
3889 }
3890
3891 EXPECT_FALSE(errors.empty());
3892}
3893
3894TEST_F(DatabaseBackedPoolTest, ErrorWithErrorCollector) {
3895 ErrorDescriptorDatabase error_database;
3896 MockErrorCollector error_collector;
3897 DescriptorPool pool(&error_database, &error_collector);
3898
3899 EXPECT_TRUE(pool.FindFileByName("error.proto") == NULL);
3900 EXPECT_EQ(
3901 "error.proto: error.proto: OTHER: File recursively imports itself: "
3902 "error.proto -> error2.proto -> error.proto\n"
3903 "error2.proto: error2.proto: OTHER: Import \"error.proto\" was not "
3904 "found or had errors.\n"
3905 "error.proto: error.proto: OTHER: Import \"error2.proto\" was not "
3906 "found or had errors.\n",
3907 error_collector.text_);
3908}
3909
3910TEST_F(DatabaseBackedPoolTest, UnittestProto) {
3911 // Try to load all of unittest.proto from a DescriptorDatabase. This should
3912 // thoroughly test all paths through DescriptorBuilder to insure that there
3913 // are no deadlocking problems when pool_->mutex_ is non-NULL.
3914 const FileDescriptor* original_file =
3915 protobuf_unittest::TestAllTypes::descriptor()->file();
3916
3917 DescriptorPoolDatabase database(*DescriptorPool::generated_pool());
3918 DescriptorPool pool(&database);
3919 const FileDescriptor* file_from_database =
3920 pool.FindFileByName(original_file->name());
3921
3922 ASSERT_TRUE(file_from_database != NULL);
3923
3924 FileDescriptorProto original_file_proto;
3925 original_file->CopyTo(&original_file_proto);
3926
3927 FileDescriptorProto file_from_database_proto;
3928 file_from_database->CopyTo(&file_from_database_proto);
3929
3930 EXPECT_EQ(original_file_proto.DebugString(),
3931 file_from_database_proto.DebugString());
3932}
3933
3934TEST_F(DatabaseBackedPoolTest, DoesntRetryDbUnnecessarily) {
3935 // Searching for a child of an existing descriptor should never fall back
3936 // to the DescriptorDatabase even if it isn't found, because we know all
3937 // children are already loaded.
3938 CallCountingDatabase call_counter(&database_);
3939 DescriptorPool pool(&call_counter);
3940
3941 const FileDescriptor* file = pool.FindFileByName("foo.proto");
3942 ASSERT_TRUE(file != NULL);
3943 const Descriptor* foo = pool.FindMessageTypeByName("Foo");
3944 ASSERT_TRUE(foo != NULL);
3945 const EnumDescriptor* test_enum = pool.FindEnumTypeByName("TestEnum");
3946 ASSERT_TRUE(test_enum != NULL);
3947 const ServiceDescriptor* test_service = pool.FindServiceByName("TestService");
3948 ASSERT_TRUE(test_service != NULL);
3949
3950 EXPECT_NE(0, call_counter.call_count_);
3951 call_counter.Clear();
3952
3953 EXPECT_TRUE(foo->FindFieldByName("no_such_field") == NULL);
3954 EXPECT_TRUE(foo->FindExtensionByName("no_such_extension") == NULL);
3955 EXPECT_TRUE(foo->FindNestedTypeByName("NoSuchMessageType") == NULL);
3956 EXPECT_TRUE(foo->FindEnumTypeByName("NoSuchEnumType") == NULL);
3957 EXPECT_TRUE(foo->FindEnumValueByName("NO_SUCH_VALUE") == NULL);
3958 EXPECT_TRUE(test_enum->FindValueByName("NO_SUCH_VALUE") == NULL);
3959 EXPECT_TRUE(test_service->FindMethodByName("NoSuchMethod") == NULL);
3960
3961 EXPECT_TRUE(file->FindMessageTypeByName("NoSuchMessageType") == NULL);
3962 EXPECT_TRUE(file->FindEnumTypeByName("NoSuchEnumType") == NULL);
3963 EXPECT_TRUE(file->FindEnumValueByName("NO_SUCH_VALUE") == NULL);
3964 EXPECT_TRUE(file->FindServiceByName("NO_SUCH_VALUE") == NULL);
3965 EXPECT_TRUE(file->FindExtensionByName("no_such_extension") == NULL);
3966 EXPECT_EQ(0, call_counter.call_count_);
3967}
3968
3969TEST_F(DatabaseBackedPoolTest, DoesntReloadFilesUncesessarily) {
3970 // If FindFileContainingSymbol() or FindFileContainingExtension() return a
3971 // file that is already in the DescriptorPool, it should not attempt to
3972 // reload the file.
3973 FalsePositiveDatabase false_positive_database(&database_);
3974 MockErrorCollector error_collector;
3975 DescriptorPool pool(&false_positive_database, &error_collector);
3976
3977 // First make sure foo.proto is loaded.
3978 const Descriptor* foo = pool.FindMessageTypeByName("Foo");
3979 ASSERT_TRUE(foo != NULL);
3980
3981 // Try inducing false positives.
3982 EXPECT_TRUE(pool.FindMessageTypeByName("NoSuchSymbol") == NULL);
3983 EXPECT_TRUE(pool.FindExtensionByNumber(foo, 22) == NULL);
3984
3985 // No errors should have been reported. (If foo.proto was incorrectly
3986 // loaded multiple times, errors would have been reported.)
3987 EXPECT_EQ("", error_collector.text_);
3988}
3989
3990TEST_F(DatabaseBackedPoolTest, DoesntReloadKnownBadFiles) {
3991 ErrorDescriptorDatabase error_database;
3992 MockErrorCollector error_collector;
3993 DescriptorPool pool(&error_database, &error_collector);
3994
3995 EXPECT_TRUE(pool.FindFileByName("error.proto") == NULL);
3996 error_collector.text_.clear();
3997 EXPECT_TRUE(pool.FindFileByName("error.proto") == NULL);
3998 EXPECT_EQ("", error_collector.text_);
3999}
4000
kenton@google.com2d6daa72009-01-22 01:27:00 +00004001TEST_F(DatabaseBackedPoolTest, DoesntFallbackOnWrongType) {
4002 // If a lookup finds a symbol of the wrong type (e.g. we pass a type name
4003 // to FindFieldByName()), we should fail fast, without checking the fallback
4004 // database.
4005 CallCountingDatabase call_counter(&database_);
4006 DescriptorPool pool(&call_counter);
4007
4008 const FileDescriptor* file = pool.FindFileByName("foo.proto");
4009 ASSERT_TRUE(file != NULL);
4010 const Descriptor* foo = pool.FindMessageTypeByName("Foo");
4011 ASSERT_TRUE(foo != NULL);
4012 const EnumDescriptor* test_enum = pool.FindEnumTypeByName("TestEnum");
4013 ASSERT_TRUE(test_enum != NULL);
4014
4015 EXPECT_NE(0, call_counter.call_count_);
4016 call_counter.Clear();
4017
4018 EXPECT_TRUE(pool.FindMessageTypeByName("TestEnum") == NULL);
4019 EXPECT_TRUE(pool.FindFieldByName("Foo") == NULL);
4020 EXPECT_TRUE(pool.FindExtensionByName("Foo") == NULL);
4021 EXPECT_TRUE(pool.FindEnumTypeByName("Foo") == NULL);
4022 EXPECT_TRUE(pool.FindEnumValueByName("Foo") == NULL);
4023 EXPECT_TRUE(pool.FindServiceByName("Foo") == NULL);
4024 EXPECT_TRUE(pool.FindMethodByName("Foo") == NULL);
4025
4026 EXPECT_EQ(0, call_counter.call_count_);
4027}
4028
kenton@google.comfccb1462009-12-18 02:11:36 +00004029// ===================================================================
4030
4031
kenton@google.com2d6daa72009-01-22 01:27:00 +00004032} // namespace descriptor_unittest
temporal40ee5512008-07-10 02:12:20 +00004033} // namespace protobuf
4034} // namespace google