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