extension_set_unittest.cc revision fbaaef999ba563838ebd00874ed8a1c01fbf286d
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#include <google/protobuf/extension_set.h> 36#include <google/protobuf/unittest.pb.h> 37#include <google/protobuf/test_util.h> 38#include <google/protobuf/io/coded_stream.h> 39#include <google/protobuf/io/zero_copy_stream_impl.h> 40 41#include <google/protobuf/stubs/common.h> 42#include <google/protobuf/testing/googletest.h> 43#include <gtest/gtest.h> 44#include <google/protobuf/stubs/stl_util-inl.h> 45 46namespace google { 47namespace protobuf { 48namespace internal { 49namespace { 50 51// This test closely mirrors google/protobuf/compiler/cpp/unittest.cc 52// except that it uses extensions rather than regular fields. 53 54TEST(ExtensionSetTest, Defaults) { 55 // Check that all default values are set correctly in the initial message. 56 unittest::TestAllExtensions message; 57 58 TestUtil::ExpectExtensionsClear(message); 59 60 // Messages should return pointers to default instances until first use. 61 // (This is not checked by ExpectClear() since it is not actually true after 62 // the fields have been set and then cleared.) 63 EXPECT_EQ(&unittest::OptionalGroup_extension::default_instance(), 64 &message.GetExtension(unittest::optionalgroup_extension)); 65 EXPECT_EQ(&unittest::TestAllTypes::NestedMessage::default_instance(), 66 &message.GetExtension(unittest::optional_nested_message_extension)); 67 EXPECT_EQ(&unittest::ForeignMessage::default_instance(), 68 &message.GetExtension( 69 unittest::optional_foreign_message_extension)); 70 EXPECT_EQ(&unittest_import::ImportMessage::default_instance(), 71 &message.GetExtension(unittest::optional_import_message_extension)); 72} 73 74TEST(ExtensionSetTest, Accessors) { 75 // Set every field to a unique value then go back and check all those 76 // values. 77 unittest::TestAllExtensions message; 78 79 TestUtil::SetAllExtensions(&message); 80 TestUtil::ExpectAllExtensionsSet(message); 81 82 TestUtil::ModifyRepeatedExtensions(&message); 83 TestUtil::ExpectRepeatedExtensionsModified(message); 84} 85 86TEST(ExtensionSetTest, Clear) { 87 // Set every field to a unique value, clear the message, then check that 88 // it is cleared. 89 unittest::TestAllExtensions message; 90 91 TestUtil::SetAllExtensions(&message); 92 message.Clear(); 93 TestUtil::ExpectExtensionsClear(message); 94 95 // Unlike with the defaults test, we do NOT expect that requesting embedded 96 // messages will return a pointer to the default instance. Instead, they 97 // should return the objects that were created when mutable_blah() was 98 // called. 99 EXPECT_NE(&unittest::OptionalGroup_extension::default_instance(), 100 &message.GetExtension(unittest::optionalgroup_extension)); 101 EXPECT_NE(&unittest::TestAllTypes::NestedMessage::default_instance(), 102 &message.GetExtension(unittest::optional_nested_message_extension)); 103 EXPECT_NE(&unittest::ForeignMessage::default_instance(), 104 &message.GetExtension( 105 unittest::optional_foreign_message_extension)); 106 EXPECT_NE(&unittest_import::ImportMessage::default_instance(), 107 &message.GetExtension(unittest::optional_import_message_extension)); 108 109 // Make sure setting stuff again after clearing works. (This takes slightly 110 // different code paths since the objects are reused.) 111 TestUtil::SetAllExtensions(&message); 112 TestUtil::ExpectAllExtensionsSet(message); 113} 114 115TEST(ExtensionSetTest, ClearOneField) { 116 // Set every field to a unique value, then clear one value and insure that 117 // only that one value is cleared. 118 unittest::TestAllExtensions message; 119 120 TestUtil::SetAllExtensions(&message); 121 int64 original_value = 122 message.GetExtension(unittest::optional_int64_extension); 123 124 // Clear the field and make sure it shows up as cleared. 125 message.ClearExtension(unittest::optional_int64_extension); 126 EXPECT_FALSE(message.HasExtension(unittest::optional_int64_extension)); 127 EXPECT_EQ(0, message.GetExtension(unittest::optional_int64_extension)); 128 129 // Other adjacent fields should not be cleared. 130 EXPECT_TRUE(message.HasExtension(unittest::optional_int32_extension)); 131 EXPECT_TRUE(message.HasExtension(unittest::optional_uint32_extension)); 132 133 // Make sure if we set it again, then all fields are set. 134 message.SetExtension(unittest::optional_int64_extension, original_value); 135 TestUtil::ExpectAllExtensionsSet(message); 136} 137 138TEST(ExtensionSetTest, CopyFrom) { 139 unittest::TestAllExtensions message1, message2; 140 string data; 141 142 TestUtil::SetAllExtensions(&message1); 143 message2.CopyFrom(message1); 144 TestUtil::ExpectAllExtensionsSet(message2); 145} 146 147TEST(ExtensionSetTest, CopyFromUpcasted) { 148 unittest::TestAllExtensions message1, message2; 149 string data; 150 const Message& upcasted_message = message1; 151 152 TestUtil::SetAllExtensions(&message1); 153 message2.CopyFrom(upcasted_message); 154 TestUtil::ExpectAllExtensionsSet(message2); 155} 156 157TEST(ExtensionSetTest, SwapWithEmpty) { 158 unittest::TestAllExtensions message1, message2; 159 TestUtil::SetAllExtensions(&message1); 160 161 TestUtil::ExpectAllExtensionsSet(message1); 162 TestUtil::ExpectExtensionsClear(message2); 163 message1.Swap(&message2); 164 TestUtil::ExpectAllExtensionsSet(message2); 165 TestUtil::ExpectExtensionsClear(message1); 166} 167 168TEST(ExtensionSetTest, SwapWithSelf) { 169 unittest::TestAllExtensions message; 170 TestUtil::SetAllExtensions(&message); 171 172 TestUtil::ExpectAllExtensionsSet(message); 173 message.Swap(&message); 174 TestUtil::ExpectAllExtensionsSet(message); 175} 176 177TEST(ExtensionSetTest, SerializationToArray) { 178 // Serialize as TestAllExtensions and parse as TestAllTypes to insure wire 179 // compatibility of extensions. 180 // 181 // This checks serialization to a flat array by explicitly reserving space in 182 // the string and calling the generated message's 183 // SerializeWithCachedSizesToArray. 184 unittest::TestAllExtensions source; 185 unittest::TestAllTypes destination; 186 TestUtil::SetAllExtensions(&source); 187 int size = source.ByteSize(); 188 string data; 189 data.resize(size); 190 uint8* target = reinterpret_cast<uint8*>(string_as_array(&data)); 191 uint8* end = source.SerializeWithCachedSizesToArray(target); 192 EXPECT_EQ(size, end - target); 193 EXPECT_TRUE(destination.ParseFromString(data)); 194 TestUtil::ExpectAllFieldsSet(destination); 195} 196 197TEST(ExtensionSetTest, SerializationToStream) { 198 // Serialize as TestAllExtensions and parse as TestAllTypes to insure wire 199 // compatibility of extensions. 200 // 201 // This checks serialization to an output stream by creating an array output 202 // stream that can only buffer 1 byte at a time - this prevents the message 203 // from ever jumping to the fast path, ensuring that serialization happens via 204 // the CodedOutputStream. 205 unittest::TestAllExtensions source; 206 unittest::TestAllTypes destination; 207 TestUtil::SetAllExtensions(&source); 208 int size = source.ByteSize(); 209 string data; 210 data.resize(size); 211 { 212 io::ArrayOutputStream array_stream(string_as_array(&data), size, 1); 213 io::CodedOutputStream output_stream(&array_stream); 214 source.SerializeWithCachedSizes(&output_stream); 215 ASSERT_FALSE(output_stream.HadError()); 216 } 217 EXPECT_TRUE(destination.ParseFromString(data)); 218 TestUtil::ExpectAllFieldsSet(destination); 219} 220 221TEST(ExtensionSetTest, PackedSerializationToArray) { 222 // Serialize as TestPackedExtensions and parse as TestPackedTypes to insure 223 // wire compatibility of extensions. 224 // 225 // This checks serialization to a flat array by explicitly reserving space in 226 // the string and calling the generated message's 227 // SerializeWithCachedSizesToArray. 228 unittest::TestPackedExtensions source; 229 unittest::TestPackedTypes destination; 230 TestUtil::SetPackedExtensions(&source); 231 int size = source.ByteSize(); 232 string data; 233 data.resize(size); 234 uint8* target = reinterpret_cast<uint8*>(string_as_array(&data)); 235 uint8* end = source.SerializeWithCachedSizesToArray(target); 236 EXPECT_EQ(size, end - target); 237 EXPECT_TRUE(destination.ParseFromString(data)); 238 TestUtil::ExpectPackedFieldsSet(destination); 239} 240 241TEST(ExtensionSetTest, PackedSerializationToStream) { 242 // Serialize as TestPackedExtensions and parse as TestPackedTypes to insure 243 // wire compatibility of extensions. 244 // 245 // This checks serialization to an output stream by creating an array output 246 // stream that can only buffer 1 byte at a time - this prevents the message 247 // from ever jumping to the fast path, ensuring that serialization happens via 248 // the CodedOutputStream. 249 unittest::TestPackedExtensions source; 250 unittest::TestPackedTypes destination; 251 TestUtil::SetPackedExtensions(&source); 252 int size = source.ByteSize(); 253 string data; 254 data.resize(size); 255 { 256 io::ArrayOutputStream array_stream(string_as_array(&data), size, 1); 257 io::CodedOutputStream output_stream(&array_stream); 258 source.SerializeWithCachedSizes(&output_stream); 259 ASSERT_FALSE(output_stream.HadError()); 260 } 261 EXPECT_TRUE(destination.ParseFromString(data)); 262 TestUtil::ExpectPackedFieldsSet(destination); 263} 264 265TEST(ExtensionSetTest, Parsing) { 266 // Serialize as TestAllTypes and parse as TestAllExtensions. 267 unittest::TestAllTypes source; 268 unittest::TestAllExtensions destination; 269 string data; 270 271 TestUtil::SetAllFields(&source); 272 source.SerializeToString(&data); 273 EXPECT_TRUE(destination.ParseFromString(data)); 274 TestUtil::ExpectAllExtensionsSet(destination); 275} 276 277TEST(ExtensionSetTest, PackedParsing) { 278 // Serialize as TestPackedTypes and parse as TestPackedExtensions. 279 unittest::TestPackedTypes source; 280 unittest::TestPackedExtensions destination; 281 string data; 282 283 TestUtil::SetPackedFields(&source); 284 source.SerializeToString(&data); 285 EXPECT_TRUE(destination.ParseFromString(data)); 286 TestUtil::ExpectPackedExtensionsSet(destination); 287} 288 289TEST(ExtensionSetTest, IsInitialized) { 290 // Test that IsInitialized() returns false if required fields in nested 291 // extensions are missing. 292 unittest::TestAllExtensions message; 293 294 EXPECT_TRUE(message.IsInitialized()); 295 296 message.MutableExtension(unittest::TestRequired::single); 297 EXPECT_FALSE(message.IsInitialized()); 298 299 message.MutableExtension(unittest::TestRequired::single)->set_a(1); 300 EXPECT_FALSE(message.IsInitialized()); 301 message.MutableExtension(unittest::TestRequired::single)->set_b(2); 302 EXPECT_FALSE(message.IsInitialized()); 303 message.MutableExtension(unittest::TestRequired::single)->set_c(3); 304 EXPECT_TRUE(message.IsInitialized()); 305 306 message.AddExtension(unittest::TestRequired::multi); 307 EXPECT_FALSE(message.IsInitialized()); 308 309 message.MutableExtension(unittest::TestRequired::multi, 0)->set_a(1); 310 EXPECT_FALSE(message.IsInitialized()); 311 message.MutableExtension(unittest::TestRequired::multi, 0)->set_b(2); 312 EXPECT_FALSE(message.IsInitialized()); 313 message.MutableExtension(unittest::TestRequired::multi, 0)->set_c(3); 314 EXPECT_TRUE(message.IsInitialized()); 315} 316 317TEST(ExtensionSetTest, MutableString) { 318 // Test the mutable string accessors. 319 unittest::TestAllExtensions message; 320 321 message.MutableExtension(unittest::optional_string_extension)->assign("foo"); 322 EXPECT_TRUE(message.HasExtension(unittest::optional_string_extension)); 323 EXPECT_EQ("foo", message.GetExtension(unittest::optional_string_extension)); 324 325 message.AddExtension(unittest::repeated_string_extension)->assign("bar"); 326 ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_string_extension)); 327 EXPECT_EQ("bar", 328 message.GetExtension(unittest::repeated_string_extension, 0)); 329} 330 331TEST(ExtensionSetTest, SpaceUsedExcludingSelf) { 332 // Scalar primitive extensions should increase the extension set size by a 333 // minimum of the size of the primitive type. 334#define TEST_SCALAR_EXTENSIONS_SPACE_USED(type, value) \ 335 do { \ 336 unittest::TestAllExtensions message; \ 337 const int base_size = message.SpaceUsed(); \ 338 message.SetExtension(unittest::optional_##type##_extension, value); \ 339 int min_expected_size = base_size + \ 340 sizeof(message.GetExtension(unittest::optional_##type##_extension)); \ 341 EXPECT_LE(min_expected_size, message.SpaceUsed()); \ 342 } while (0) 343 344 TEST_SCALAR_EXTENSIONS_SPACE_USED(int32 , 101); 345 TEST_SCALAR_EXTENSIONS_SPACE_USED(int64 , 102); 346 TEST_SCALAR_EXTENSIONS_SPACE_USED(uint32 , 103); 347 TEST_SCALAR_EXTENSIONS_SPACE_USED(uint64 , 104); 348 TEST_SCALAR_EXTENSIONS_SPACE_USED(sint32 , 105); 349 TEST_SCALAR_EXTENSIONS_SPACE_USED(sint64 , 106); 350 TEST_SCALAR_EXTENSIONS_SPACE_USED(fixed32 , 107); 351 TEST_SCALAR_EXTENSIONS_SPACE_USED(fixed64 , 108); 352 TEST_SCALAR_EXTENSIONS_SPACE_USED(sfixed32, 109); 353 TEST_SCALAR_EXTENSIONS_SPACE_USED(sfixed64, 110); 354 TEST_SCALAR_EXTENSIONS_SPACE_USED(float , 111); 355 TEST_SCALAR_EXTENSIONS_SPACE_USED(double , 112); 356 TEST_SCALAR_EXTENSIONS_SPACE_USED(bool , true); 357#undef TEST_SCALAR_EXTENSIONS_SPACE_USED 358 { 359 unittest::TestAllExtensions message; 360 const int base_size = message.SpaceUsed(); 361 message.SetExtension(unittest::optional_nested_enum_extension, 362 unittest::TestAllTypes::FOO); 363 int min_expected_size = base_size + 364 sizeof(message.GetExtension(unittest::optional_nested_enum_extension)); 365 EXPECT_LE(min_expected_size, message.SpaceUsed()); 366 } 367 { 368 // Strings may cause extra allocations depending on their length; ensure 369 // that gets included as well. 370 unittest::TestAllExtensions message; 371 const int base_size = message.SpaceUsed(); 372 const string s("this is a fairly large string that will cause some " 373 "allocation in order to store it in the extension"); 374 message.SetExtension(unittest::optional_string_extension, s); 375 int min_expected_size = base_size + s.length(); 376 EXPECT_LE(min_expected_size, message.SpaceUsed()); 377 } 378 { 379 // Messages also have additional allocation that need to be counted. 380 unittest::TestAllExtensions message; 381 const int base_size = message.SpaceUsed(); 382 unittest::ForeignMessage foreign; 383 foreign.set_c(42); 384 message.MutableExtension(unittest::optional_foreign_message_extension)-> 385 CopyFrom(foreign); 386 int min_expected_size = base_size + foreign.SpaceUsed(); 387 EXPECT_LE(min_expected_size, message.SpaceUsed()); 388 } 389 390 // Repeated primitive extensions will increase space used by at least a 391 // RepeatedField<T>, and will cause additional allocations when the array 392 // gets too big for the initial space. 393 // This macro: 394 // - Adds a value to the repeated extension, then clears it, establishing 395 // the base size. 396 // - Adds a small number of values, testing that it doesn't increase the 397 // SpaceUsed() 398 // - Adds a large number of values (requiring allocation in the repeated 399 // field), and ensures that that allocation is included in SpaceUsed() 400#define TEST_REPEATED_EXTENSIONS_SPACE_USED(type, cpptype, value) \ 401 do { \ 402 unittest::TestAllExtensions message; \ 403 const int base_size = message.SpaceUsed(); \ 404 int min_expected_size = sizeof(RepeatedField<cpptype>) + base_size; \ 405 message.AddExtension(unittest::repeated_##type##_extension, value); \ 406 message.ClearExtension(unittest::repeated_##type##_extension); \ 407 const int empty_repeated_field_size = message.SpaceUsed(); \ 408 EXPECT_LE(min_expected_size, empty_repeated_field_size) << #type; \ 409 message.AddExtension(unittest::repeated_##type##_extension, value); \ 410 message.AddExtension(unittest::repeated_##type##_extension, value); \ 411 EXPECT_EQ(empty_repeated_field_size, message.SpaceUsed()) << #type; \ 412 message.ClearExtension(unittest::repeated_##type##_extension); \ 413 for (int i = 0; i < 16; ++i) { \ 414 message.AddExtension(unittest::repeated_##type##_extension, value); \ 415 } \ 416 int expected_size = sizeof(cpptype) * 16 + empty_repeated_field_size; \ 417 EXPECT_EQ(expected_size, message.SpaceUsed()) << #type; \ 418 } while (0) 419 420 TEST_REPEATED_EXTENSIONS_SPACE_USED(int32 , int32 , 101); 421 TEST_REPEATED_EXTENSIONS_SPACE_USED(int64 , int64 , 102); 422 TEST_REPEATED_EXTENSIONS_SPACE_USED(uint32 , uint32, 103); 423 TEST_REPEATED_EXTENSIONS_SPACE_USED(uint64 , uint64, 104); 424 TEST_REPEATED_EXTENSIONS_SPACE_USED(sint32 , int32 , 105); 425 TEST_REPEATED_EXTENSIONS_SPACE_USED(sint64 , int64 , 106); 426 TEST_REPEATED_EXTENSIONS_SPACE_USED(fixed32 , uint32, 107); 427 TEST_REPEATED_EXTENSIONS_SPACE_USED(fixed64 , uint64, 108); 428 TEST_REPEATED_EXTENSIONS_SPACE_USED(sfixed32, int32 , 109); 429 TEST_REPEATED_EXTENSIONS_SPACE_USED(sfixed64, int64 , 110); 430 TEST_REPEATED_EXTENSIONS_SPACE_USED(float , float , 111); 431 TEST_REPEATED_EXTENSIONS_SPACE_USED(double , double, 112); 432 TEST_REPEATED_EXTENSIONS_SPACE_USED(bool , bool , true); 433 TEST_REPEATED_EXTENSIONS_SPACE_USED(nested_enum, int, 434 unittest::TestAllTypes::FOO); 435#undef TEST_REPEATED_EXTENSIONS_SPACE_USED 436 // Repeated strings 437 { 438 unittest::TestAllExtensions message; 439 const int base_size = message.SpaceUsed(); 440 int min_expected_size = sizeof(RepeatedPtrField<string>) + base_size; 441 const string value(256, 'x'); 442 // Once items are allocated, they may stick around even when cleared so 443 // without the hardcore memory management accessors there isn't a notion of 444 // the empty repeated field memory usage as there is with primitive types. 445 for (int i = 0; i < 16; ++i) { 446 message.AddExtension(unittest::repeated_string_extension, value); 447 } 448 min_expected_size += (sizeof(value) + value.size()) * 16; 449 EXPECT_LE(min_expected_size, message.SpaceUsed()); 450 } 451 // Repeated messages 452 { 453 unittest::TestAllExtensions message; 454 const int base_size = message.SpaceUsed(); 455 int min_expected_size = sizeof(RepeatedPtrField<unittest::ForeignMessage>) + 456 base_size; 457 unittest::ForeignMessage prototype; 458 prototype.set_c(2); 459 for (int i = 0; i < 16; ++i) { 460 message.AddExtension(unittest::repeated_foreign_message_extension)-> 461 CopyFrom(prototype); 462 } 463 min_expected_size += 16 * prototype.SpaceUsed(); 464 EXPECT_LE(min_expected_size, message.SpaceUsed()); 465 } 466} 467 468#ifdef GTEST_HAS_DEATH_TEST 469 470TEST(ExtensionSetTest, InvalidEnumDeath) { 471 unittest::TestAllExtensions message; 472 EXPECT_DEBUG_DEATH( 473 message.SetExtension(unittest::optional_foreign_enum_extension, 474 static_cast<unittest::ForeignEnum>(53)), 475 "IsValid"); 476} 477 478#endif // GTEST_HAS_DEATH_TEST 479 480} // namespace 481} // namespace internal 482} // namespace protobuf 483} // namespace google 484