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