Index: third_party/protobuf/src/google/protobuf/map_test.cc |
diff --git a/third_party/protobuf/src/google/protobuf/map_test.cc b/third_party/protobuf/src/google/protobuf/map_test.cc |
index 9d4d6c13d057c0314281249b6563a7020e9d50ad..d0a34d01f58d156879dde1e0c4f6a0bb1149df23 100644 |
--- a/third_party/protobuf/src/google/protobuf/map_test.cc |
+++ b/third_party/protobuf/src/google/protobuf/map_test.cc |
@@ -50,7 +50,6 @@ |
#include <google/protobuf/stubs/casts.h> |
#include <google/protobuf/stubs/logging.h> |
#include <google/protobuf/stubs/common.h> |
-#include <google/protobuf/stubs/scoped_ptr.h> |
#include <google/protobuf/stubs/stringprintf.h> |
#include <google/protobuf/testing/file.h> |
#include <google/protobuf/arena_test_util.h> |
@@ -75,8 +74,10 @@ |
#include <google/protobuf/io/tokenizer.h> |
#include <google/protobuf/io/zero_copy_stream_impl.h> |
#include <google/protobuf/util/time_util.h> |
+#include <google/protobuf/util/message_differencer.h> |
#include <google/protobuf/stubs/strutil.h> |
#include <google/protobuf/stubs/substitute.h> |
+#include <gmock/gmock.h> |
#include <google/protobuf/testing/googletest.h> |
#include <gtest/gtest.h> |
@@ -297,7 +298,7 @@ TEST_P(MapImplTest, IteratorBasic) { |
template <typename Iterator> |
static int64 median(Iterator i0, Iterator i1) { |
- vector<int64> v(i0, i1); |
+ std::vector<int64> v(i0, i1); |
std::nth_element(v.begin(), v.begin() + v.size() / 2, v.end()); |
return v[v.size() / 2]; |
} |
@@ -333,7 +334,7 @@ TEST_P(MapImplTest, BeginIsFast) { |
GOOGLE_DCHECK_GE(last_key, 0); |
map[last_key] = last_key ^ 1; |
} |
- vector<int64> times; |
+ std::vector<int64> times; |
// We're going to do map.erase(map.begin()) over and over again. But, |
// just in case one iteration is fast compared to the granularity of |
// our time keeping, we measure kChunkSize iterations per outer-loop iter. |
@@ -378,7 +379,7 @@ TEST_P(MapImplTest, HashFlood) { |
// 1024 (or 512 or 2048 or ...) entries. This assumes that map_ uses powers |
// of 2 for table sizes, and that it's sufficient to "flood" with respect to |
// the low bits of the output of map_.hash_function(). |
- vector<int64> times; |
+ std::vector<int64> times; |
std::set<int>::iterator it = s.begin(); |
int count = 0; |
do { |
@@ -502,10 +503,10 @@ static void StressTestIterators(int n, bool test_old_style_proto2_maps) { |
// Test old iterator vs new iterator, with table modification in between. |
TestOldVersusNewIterator<Map<int, int>::const_iterator>(n % 3, &m); |
TestOldVersusNewIterator<Map<int, int>::iterator>(n % (1 + (n / 40)), &m); |
- // Finally, ensure erase(iterator) doesn't reorder anything, becuase that is |
+ // Finally, ensure erase(iterator) doesn't reorder anything, because that is |
// what its documentation says. |
m[last_key] = m[last_key ^ 999] = 0; |
- vector<Map<int, int>::iterator> v; |
+ std::vector<Map<int, int>::iterator> v; |
v.reserve(m.size()); |
int position_of_last_key = 0; |
for (Map<int, int>::iterator it = m.begin(); it != m.end(); ++it) { |
@@ -562,7 +563,7 @@ TEST_P(MapImplTest, EraseRevalidates) { |
map_[3] = map_[13] = map_[20] = 0; |
const int initial_size = map_.size(); |
EXPECT_EQ(3, initial_size); |
- vector<Map<int, int>::iterator> v; |
+ std::vector<Map<int, int>::iterator> v; |
for (Map<int, int>::iterator it = map_.begin(); it != map_.end(); ++it) { |
v.push_back(it); |
} |
@@ -915,6 +916,55 @@ TEST_P(MapImplTest, ConvertToStdVectorOfPairs) { |
EXPECT_EQ(101, std_vec[0].second); |
} |
+TEST_P(MapImplTest, SwapSameStyle) { |
+ Map<int32, int32> another(GetParam()); // same old_style_ value |
+ map_[9398] = 41999; |
+ another[9398] = 41999; |
+ another[8070] = 42056; |
+ another.swap(map_); |
+ EXPECT_THAT(another, testing::UnorderedElementsAre( |
+ testing::Pair(9398, 41999))); |
+ EXPECT_THAT(map_, testing::UnorderedElementsAre( |
+ testing::Pair(8070, 42056), |
+ testing::Pair(9398, 41999))); |
+} |
+ |
+TEST_P(MapImplTest, SwapDifferentStyle) { |
+ Map<int32, int32> another(!GetParam()); // different old_style_ value |
+ map_[9398] = 41999; |
+ another[9398] = 41999; |
+ another[8070] = 42056; |
+ another.swap(map_); |
+ EXPECT_THAT(another, testing::UnorderedElementsAre( |
+ testing::Pair(9398, 41999))); |
+ EXPECT_THAT(map_, testing::UnorderedElementsAre( |
+ testing::Pair(8070, 42056), |
+ testing::Pair(9398, 41999))); |
+} |
+ |
+TEST_P(MapImplTest, SwapArena) { |
+ Arena arena1, arena2; |
+ Map<int32, int32> m1(&arena1, false); |
+ Map<int32, int32> m2(&arena2, false); |
+ map_[9398] = 41999; |
+ m1[9398] = 41999; |
+ m1[8070] = 42056; |
+ m2[10244] = 10247; |
+ m2[8070] = 42056; |
+ m1.swap(map_); |
+ EXPECT_THAT(m1, testing::UnorderedElementsAre( |
+ testing::Pair(9398, 41999))); |
+ EXPECT_THAT(map_, testing::UnorderedElementsAre( |
+ testing::Pair(8070, 42056), |
+ testing::Pair(9398, 41999))); |
+ m2.swap(m1); |
+ EXPECT_THAT(m1, testing::UnorderedElementsAre( |
+ testing::Pair(8070, 42056), |
+ testing::Pair(10244, 10247))); |
+ EXPECT_THAT(m2, testing::UnorderedElementsAre( |
+ testing::Pair(9398, 41999))); |
+} |
+ |
INSTANTIATE_TEST_CASE_P(BoolSequence, MapImplTest, testing::Bool()); |
// Map Field Reflection Test ======================================== |
@@ -2106,6 +2156,76 @@ TEST(GeneratedMapFieldTest, DuplicatedKeyWireFormat) { |
EXPECT_TRUE(message.ParseFromString(data)); |
EXPECT_EQ(1, message.map_int32_int32().size()); |
EXPECT_EQ(1, message.map_int32_int32().at(2)); |
+ |
+ // A similar test, but with a map from int to a message type. |
+ // Again, we want to be sure that the "second one wins" when |
+ // there are two separate entries with the same key. |
+ const int key = 99; |
+ unittest::TestRequiredMessageMap map_message; |
+ unittest::TestRequired with_dummy4; |
+ with_dummy4.set_a(0); |
+ with_dummy4.set_b(0); |
+ with_dummy4.set_c(0); |
+ with_dummy4.set_dummy4(11); |
+ (*map_message.mutable_map_field())[key] = with_dummy4; |
+ string s = map_message.SerializeAsString(); |
+ unittest::TestRequired with_dummy5; |
+ with_dummy5.set_a(0); |
+ with_dummy5.set_b(0); |
+ with_dummy5.set_c(0); |
+ with_dummy5.set_dummy5(12); |
+ (*map_message.mutable_map_field())[key] = with_dummy5; |
+ string both = s + map_message.SerializeAsString(); |
+ // We don't expect a merge now. The "second one wins." |
+ ASSERT_TRUE(map_message.ParseFromString(both)); |
+ ASSERT_EQ(1, map_message.map_field().size()); |
+ ASSERT_EQ(1, map_message.map_field().count(key)); |
+ EXPECT_EQ(0, map_message.map_field().find(key)->second.a()); |
+ EXPECT_EQ(0, map_message.map_field().find(key)->second.b()); |
+ EXPECT_EQ(0, map_message.map_field().find(key)->second.c()); |
+ EXPECT_FALSE(map_message.map_field().find(key)->second.has_dummy4()); |
+ ASSERT_TRUE(map_message.map_field().find(key)->second.has_dummy5()); |
+ EXPECT_EQ(12, map_message.map_field().find(key)->second.dummy5()); |
+} |
+ |
+// Exhaustive combinations of keys, values, and junk in any order. |
+// This re-tests some of the things tested above, but if it fails |
+// it's more work to determine what went wrong, so it isn't necessarily |
+// bad that we have the simpler tests too. |
+TEST(GeneratedMapFieldTest, KeysValuesUnknownsWireFormat) { |
+ unittest::TestMap message; |
+ const int kMaxNumKeysAndValuesAndJunk = 4; |
+ const char kKeyTag = 0x08; |
+ const char kValueTag = 0x10; |
+ const char kJunkTag = 0x20; |
+ for (int items = 0; items <= kMaxNumKeysAndValuesAndJunk; items++) { |
+ string data = "\x0A"; |
+ // Encode length of what will follow. |
+ data.push_back(items * 2); |
+ static const int kBitsOfIPerItem = 4; |
+ static const int mask = (1 << kBitsOfIPerItem) - 1; |
+ // Each iteration of the following is a test. It uses i as bit vector |
+ // encoding the keys and values to put in the wire format. |
+ for (int i = 0; i < (1 << (items * kBitsOfIPerItem)); i++) { |
+ string wire_format = data; |
+ int expected_key = 0; |
+ int expected_value = 0; |
+ for (int k = i, j = 0; j < items; j++, k >>= kBitsOfIPerItem) { |
+ bool is_key = k & 0x1; |
+ bool is_value = !is_key && (k & 0x2); |
+ wire_format.push_back(is_key ? kKeyTag : |
+ is_value ? kValueTag : kJunkTag); |
+ char c = static_cast<char>(k & mask) >> 2; // One char after the tag. |
+ wire_format.push_back(c); |
+ if (is_key) expected_key = static_cast<int>(c); |
+ if (is_value) expected_value = static_cast<int>(c); |
+ ASSERT_TRUE(message.ParseFromString(wire_format)); |
+ ASSERT_EQ(1, message.map_int32_int32().size()); |
+ ASSERT_EQ(expected_key, message.map_int32_int32().begin()->first); |
+ ASSERT_EQ(expected_value, message.map_int32_int32().begin()->second); |
+ } |
+ } |
+ } |
} |
TEST(GeneratedMapFieldTest, DuplicatedValueWireFormat) { |
@@ -2189,6 +2309,74 @@ TEST(GeneratedMapFieldTest, IsInitialized) { |
EXPECT_TRUE(map_message.IsInitialized()); |
} |
+TEST(GeneratedMapFieldTest, MessagesMustMerge) { |
+ unittest::TestRequiredMessageMap map_message; |
+ unittest::TestRequired with_dummy4; |
+ with_dummy4.set_a(97); |
+ with_dummy4.set_b(0); |
+ with_dummy4.set_c(0); |
+ with_dummy4.set_dummy4(98); |
+ |
+ EXPECT_TRUE(with_dummy4.IsInitialized()); |
+ (*map_message.mutable_map_field())[0] = with_dummy4; |
+ EXPECT_TRUE(map_message.IsInitialized()); |
+ string s = map_message.SerializeAsString(); |
+ |
+ // Modify s so that there are two values in the entry for key 0. |
+ // The first will have no value for c. The second will have no value for a. |
+ // Those are required fields. Also, make some other little changes, to |
+ // ensure we are merging the two values (because they're messages). |
+ ASSERT_EQ(s.size() - 2, s[1]); // encoding of the length of what follows |
+ string encoded_val(s.data() + 4, s.data() + s.size()); |
+ // In s, change the encoding of c to an encoding of dummy32. |
+ s[s.size() - 3] -= 8; |
+ // Make encoded_val slightly different from what's in s. |
+ encoded_val[encoded_val.size() - 1] += 33; // Encode c = 33. |
+ for (int i = 0; i < encoded_val.size(); i++) { |
+ if (encoded_val[i] == 97) { |
+ // Encode b = 91 instead of a = 97. But this won't matter, because |
+ // we also encode b = 0 right after this. The point is to leave out |
+ // a required field, and make sure the parser doesn't complain, because |
+ // every required field is set after the merge of the two values. |
+ encoded_val[i - 1] += 16; |
+ encoded_val[i] = 91; |
+ } else if (encoded_val[i] == 98) { |
+ // Encode dummy5 = 99 instead of dummy4 = 98. |
+ encoded_val[i - 1] += 8; // The tag for dummy5 is 8 more. |
+ encoded_val[i]++; |
+ break; |
+ } |
+ } |
+ |
+ s += encoded_val; // Add the second message. |
+ s[1] += encoded_val.size(); // Adjust encoded size. |
+ |
+ // Test key then value then value. |
+ int key = 0; |
+ ASSERT_TRUE(map_message.ParseFromString(s)); |
+ ASSERT_EQ(1, map_message.map_field().size()); |
+ ASSERT_EQ(1, map_message.map_field().count(key)); |
+ EXPECT_EQ(97, map_message.map_field().find(key)->second.a()); |
+ EXPECT_EQ(0, map_message.map_field().find(key)->second.b()); |
+ EXPECT_EQ(33, map_message.map_field().find(key)->second.c()); |
+ EXPECT_EQ(98, map_message.map_field().find(key)->second.dummy4()); |
+ EXPECT_EQ(99, map_message.map_field().find(key)->second.dummy5()); |
+ |
+ // Test key then value then value then key. |
+ s.push_back(s[2]); // Copy the key's tag. |
+ key = 19; |
+ s.push_back(key); // Second key is 19 instead of 0. |
+ s[1] += 2; // Adjust encoded size. |
+ ASSERT_TRUE(map_message.ParseFromString(s)); |
+ ASSERT_EQ(1, map_message.map_field().size()); |
+ ASSERT_EQ(1, map_message.map_field().count(key)); |
+ EXPECT_EQ(97, map_message.map_field().find(key)->second.a()); |
+ EXPECT_EQ(0, map_message.map_field().find(key)->second.b()); |
+ EXPECT_EQ(33, map_message.map_field().find(key)->second.c()); |
+ EXPECT_EQ(98, map_message.map_field().find(key)->second.dummy4()); |
+ EXPECT_EQ(99, map_message.map_field().find(key)->second.dummy5()); |
+} |
+ |
// Generated Message Reflection Test ================================ |
TEST(GeneratedMapFieldReflectionTest, SpaceUsed) { |
@@ -2249,7 +2437,7 @@ TEST(GeneratedMapFieldReflectionTest, SwapFields) { |
MapTestUtil::SetMapFields(&message2); |
- vector<const FieldDescriptor*> fields; |
+ std::vector<const FieldDescriptor*> fields; |
const Reflection* reflection = message1.GetReflection(); |
reflection->ListFields(message2, &fields); |
reflection->SwapFields(&message1, &message2, fields); |
@@ -2682,6 +2870,112 @@ TEST(WireFormatForMapFieldTest, MapParseHelpers) { |
} |
} |
+// Deterministic Serialization Test ========================================== |
+ |
+template <typename T> |
+static string DeterministicSerializationWithSerializePartialToCodedStream( |
+ const T& t) { |
+ const int size = t.ByteSize(); |
+ string result(size, '\0'); |
+ io::ArrayOutputStream array_stream(string_as_array(&result), size); |
+ io::CodedOutputStream output_stream(&array_stream); |
+ output_stream.SetSerializationDeterministic(true); |
+ t.SerializePartialToCodedStream(&output_stream); |
+ EXPECT_FALSE(output_stream.HadError()); |
+ EXPECT_EQ(size, output_stream.ByteCount()); |
+ return result; |
+} |
+ |
+template <typename T> |
+static string DeterministicSerializationWithSerializeToCodedStream(const T& t) { |
+ const int size = t.ByteSize(); |
+ string result(size, '\0'); |
+ io::ArrayOutputStream array_stream(string_as_array(&result), size); |
+ io::CodedOutputStream output_stream(&array_stream); |
+ output_stream.SetSerializationDeterministic(true); |
+ t.SerializeToCodedStream(&output_stream); |
+ EXPECT_FALSE(output_stream.HadError()); |
+ EXPECT_EQ(size, output_stream.ByteCount()); |
+ return result; |
+} |
+ |
+template <typename T> |
+static string DeterministicSerialization(const T& t) { |
+ const int size = t.ByteSize(); |
+ string result(size, '\0'); |
+ io::ArrayOutputStream array_stream(string_as_array(&result), size); |
+ io::CodedOutputStream output_stream(&array_stream); |
+ output_stream.SetSerializationDeterministic(true); |
+ t.SerializeWithCachedSizes(&output_stream); |
+ EXPECT_FALSE(output_stream.HadError()); |
+ EXPECT_EQ(size, output_stream.ByteCount()); |
+ EXPECT_EQ(result, DeterministicSerializationWithSerializeToCodedStream(t)); |
+ EXPECT_EQ(result, |
+ DeterministicSerializationWithSerializePartialToCodedStream(t)); |
+ return result; |
+} |
+ |
+// Helper to test the serialization of the first arg against a golden file. |
+static void TestDeterministicSerialization(const protobuf_unittest::TestMaps& t, |
+ const string& filename) { |
+ string expected; |
+ GOOGLE_CHECK_OK(File::GetContents( |
+ TestSourceDir() + "/google/protobuf/testdata/" + filename, |
+ &expected, true)); |
+ const string actual = DeterministicSerialization(t); |
+ EXPECT_EQ(expected, actual); |
+ protobuf_unittest::TestMaps u; |
+ EXPECT_TRUE(u.ParseFromString(actual)); |
+ EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(u, t)); |
+} |
+ |
+// Helper for MapSerializationTest. Return a 7-bit ASCII string. |
+static string ConstructKey(uint64 n) { |
+ string s(n % static_cast<uint64>(9), '\0'); |
+ if (s.empty()) { |
+ return StrCat(n); |
+ } else { |
+ while (n != 0) { |
+ s[n % s.size()] = (n >> 10) & 0x7f; |
+ n /= 888; |
+ } |
+ return s; |
+ } |
+} |
+ |
+TEST(MapSerializationTest, Deterministic) { |
+ const int kIters = 25; |
+ protobuf_unittest::TestMaps t; |
+ protobuf_unittest::TestIntIntMap inner; |
+ (*inner.mutable_m())[0] = (*inner.mutable_m())[10] = |
+ (*inner.mutable_m())[-200] = 0; |
+ uint64 frog = 9; |
+ const uint64 multiplier = 0xa29cd16f; |
+ for (int i = 0; i < kIters; i++) { |
+ const int32 i32 = static_cast<int32>(frog & 0xffffffff); |
+ const uint32 u32 = static_cast<uint32>(i32) * 91919; |
+ const int64 i64 = static_cast<int64>(frog); |
+ const uint64 u64 = frog * static_cast<uint64>(187321); |
+ const bool b = i32 > 0; |
+ const string s = ConstructKey(frog); |
+ (*inner.mutable_m())[i] = i32; |
+ (*t.mutable_m_int32())[i32] = (*t.mutable_m_sint32())[i32] = |
+ (*t.mutable_m_sfixed32())[i32] = inner; |
+ (*t.mutable_m_uint32())[u32] = (*t.mutable_m_fixed32())[u32] = inner; |
+ (*t.mutable_m_int64())[i64] = (*t.mutable_m_sint64())[i64] = |
+ (*t.mutable_m_sfixed64())[i64] = inner; |
+ (*t.mutable_m_uint64())[u64] = (*t.mutable_m_fixed64())[u64] = inner; |
+ (*t.mutable_m_bool())[b] = inner; |
+ (*t.mutable_m_string())[s] = inner; |
+ (*t.mutable_m_string())[s + string(1 << (u32 % static_cast<uint32>(9)), |
+ b)] = inner; |
+ inner.mutable_m()->erase(i); |
+ frog = frog * multiplier + i; |
+ frog ^= (frog >> 41); |
+ } |
+ TestDeterministicSerialization(t, "golden_message_maps"); |
+} |
+ |
// Text Format Test ================================================= |
TEST(TextFormatMapTest, SerializeAndParse) { |
@@ -2719,6 +3013,18 @@ TEST(TextFormatMapTest, Sorted) { |
EXPECT_EQ(message2.DebugString(), expected_text); |
} |
+TEST(TextFormatMapTest, ParseCorruptedString) { |
+ string serialized_message; |
+ GOOGLE_CHECK_OK(File::GetContents( |
+ TestSourceDir() + |
+ "/google/protobuf/testdata/golden_message_maps", |
+ &serialized_message, true)); |
+ protobuf_unittest::TestMaps message; |
+ GOOGLE_CHECK(message.ParseFromString(serialized_message)); |
+ TestParseCorruptedString<protobuf_unittest::TestMaps, true>(message); |
+ TestParseCorruptedString<protobuf_unittest::TestMaps, false>(message); |
+} |
+ |
// arena support ================================================= |
TEST(ArenaTest, ParsingAndSerializingNoHeapAllocation) { |
@@ -2783,6 +3089,21 @@ TEST(ArenaTest, StringMapNoLeak) { |
ASSERT_FALSE(message == NULL); |
} |
+TEST(ArenaTest, IsInitialized) { |
+ // Allocate a large initial polluted block. |
+ std::vector<char> arena_block(128 * 1024); |
+ std::fill(arena_block.begin(), arena_block.end(), '\xff'); |
+ |
+ ArenaOptions options; |
+ options.initial_block = &arena_block[0]; |
+ options.initial_block_size = arena_block.size(); |
+ Arena arena(options); |
+ |
+ unittest::TestArenaMap* message = |
+ Arena::CreateMessage<unittest::TestArenaMap>(&arena); |
+ EXPECT_EQ(0, (*message->mutable_map_int32_int32())[0]); |
+} |
+ |
} // namespace internal |
} // namespace protobuf |
} // namespace google |