| 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 451b02e84a84e3f02ca5f96f6f3724ae36cf7cbb..9d4d6c13d057c0314281249b6563a7020e9d50ad 100644
|
| --- a/third_party/protobuf/src/google/protobuf/map_test.cc
|
| +++ b/third_party/protobuf/src/google/protobuf/map_test.cc
|
| @@ -28,12 +28,24 @@
|
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
| +// A hack to include windows.h first, which ensures the GetMessage macro can
|
| +// be undefined when we include <google/protobuf/stubs/common.h>
|
| +#if defined(_WIN32)
|
| +#define _WINSOCKAPI_ // to avoid re-definition in WinSock2.h
|
| +#define NOMINMAX // to avoid defining min/max macros
|
| +#include <windows.h>
|
| +#endif // _WIN32
|
| +
|
| +#include <algorithm>
|
| +#include <google/protobuf/stubs/hash.h>
|
| #include <map>
|
| #include <memory>
|
| #ifndef _SHARED_PTR_H
|
| #include <google/protobuf/stubs/shared_ptr.h>
|
| #endif
|
| +#include <set>
|
| #include <sstream>
|
| +#include <vector>
|
|
|
| #include <google/protobuf/stubs/casts.h>
|
| #include <google/protobuf/stubs/logging.h>
|
| @@ -62,6 +74,7 @@
|
| #include <google/protobuf/io/coded_stream.h>
|
| #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/stubs/strutil.h>
|
| #include <google/protobuf/stubs/substitute.h>
|
| #include <google/protobuf/testing/googletest.h>
|
| @@ -79,10 +92,11 @@ namespace internal {
|
|
|
| // Map API Test =====================================================
|
|
|
| -class MapImplTest : public ::testing::Test {
|
| +// Parameterized tests on whether to use old style maps.
|
| +class MapImplTest : public testing::TestWithParam<bool> {
|
| protected:
|
| MapImplTest()
|
| - : map_ptr_(new Map<int32, int32>),
|
| + : map_ptr_(new Map<int32, int32>(GetParam())),
|
| map_(*map_ptr_),
|
| const_map_(*map_ptr_) {
|
| EXPECT_TRUE(map_.empty());
|
| @@ -159,7 +173,7 @@ class MapImplTest : public ::testing::Test {
|
| const Map<int32, int32>& const_map_;
|
| };
|
|
|
| -TEST_F(MapImplTest, OperatorBracket) {
|
| +TEST_P(MapImplTest, OperatorBracket) {
|
| int32 key = 0;
|
| int32 value1 = 100;
|
| int32 value2 = 101;
|
| @@ -173,7 +187,7 @@ TEST_F(MapImplTest, OperatorBracket) {
|
| ExpectSingleElement(key, value2);
|
| }
|
|
|
| -TEST_F(MapImplTest, OperatorBracketNonExist) {
|
| +TEST_P(MapImplTest, OperatorBracketNonExist) {
|
| int32 key = 0;
|
| int32 default_value = 0;
|
|
|
| @@ -181,7 +195,7 @@ TEST_F(MapImplTest, OperatorBracketNonExist) {
|
| ExpectSingleElement(key, default_value);
|
| }
|
|
|
| -TEST_F(MapImplTest, MutableAt) {
|
| +TEST_P(MapImplTest, MutableAt) {
|
| int32 key = 0;
|
| int32 value1 = 100;
|
| int32 value2 = 101;
|
| @@ -195,15 +209,15 @@ TEST_F(MapImplTest, MutableAt) {
|
|
|
| #ifdef PROTOBUF_HAS_DEATH_TEST
|
|
|
| -TEST_F(MapImplTest, MutableAtNonExistDeathTest) {
|
| +TEST_P(MapImplTest, MutableAtNonExistDeathTest) {
|
| EXPECT_DEATH(map_.at(0), "");
|
| }
|
|
|
| -TEST_F(MapImplTest, ImmutableAtNonExistDeathTest) {
|
| +TEST_P(MapImplTest, ImmutableAtNonExistDeathTest) {
|
| EXPECT_DEATH(const_map_.at(0), "");
|
| }
|
|
|
| -TEST_F(MapImplTest, UsageErrors) {
|
| +TEST_P(MapImplTest, UsageErrors) {
|
| MapKey key;
|
| key.SetInt64Value(1);
|
| EXPECT_DEATH(key.GetUInt64Value(),
|
| @@ -220,23 +234,23 @@ TEST_F(MapImplTest, UsageErrors) {
|
|
|
| #endif // PROTOBUF_HAS_DEATH_TEST
|
|
|
| -TEST_F(MapImplTest, CountNonExist) {
|
| +TEST_P(MapImplTest, CountNonExist) {
|
| EXPECT_EQ(0, map_.count(0));
|
| }
|
|
|
| -TEST_F(MapImplTest, MutableFindNonExist) {
|
| +TEST_P(MapImplTest, MutableFindNonExist) {
|
| EXPECT_TRUE(map_.end() == map_.find(0));
|
| }
|
|
|
| -TEST_F(MapImplTest, ImmutableFindNonExist) {
|
| +TEST_P(MapImplTest, ImmutableFindNonExist) {
|
| EXPECT_TRUE(const_map_.end() == const_map_.find(0));
|
| }
|
|
|
| -TEST_F(MapImplTest, ConstEnd) {
|
| +TEST_P(MapImplTest, ConstEnd) {
|
| EXPECT_TRUE(const_map_.end() == const_map_.cend());
|
| }
|
|
|
| -TEST_F(MapImplTest, GetReferenceFromIterator) {
|
| +TEST_P(MapImplTest, GetReferenceFromIterator) {
|
| for (int i = 0; i < 10; i++) {
|
| map_[i] = i;
|
| }
|
| @@ -259,7 +273,7 @@ TEST_F(MapImplTest, GetReferenceFromIterator) {
|
| }
|
| }
|
|
|
| -TEST_F(MapImplTest, IteratorBasic) {
|
| +TEST_P(MapImplTest, IteratorBasic) {
|
| map_[0] = 0;
|
|
|
| // Default constructible (per forward iterator requirements).
|
| @@ -281,6 +295,292 @@ TEST_F(MapImplTest, IteratorBasic) {
|
| EXPECT_TRUE(it == cit);
|
| }
|
|
|
| +template <typename Iterator>
|
| +static int64 median(Iterator i0, Iterator i1) {
|
| + vector<int64> v(i0, i1);
|
| + std::nth_element(v.begin(), v.begin() + v.size() / 2, v.end());
|
| + return v[v.size() / 2];
|
| +}
|
| +
|
| +static int64 Now() {
|
| + return google::protobuf::util::TimeUtil::TimestampToNanoseconds(
|
| + google::protobuf::util::TimeUtil::GetCurrentTime());
|
| +}
|
| +
|
| +// Arbitrary odd integers for creating test data.
|
| +static int k0 = 812398771;
|
| +static int k1 = 1312938717;
|
| +static int k2 = 1321555333;
|
| +
|
| +// A naive begin() implementation will cause begin() to get slower and slower
|
| +// if one erases elements at the "front" of the hash map, and we'd like to
|
| +// avoid that, as std::unordered_map does.
|
| +TEST_P(MapImplTest, BeginIsFast) {
|
| + // Disable this test for both new and old implementations.
|
| + if (/*GetParam()*/true) return;
|
| + Map<int32, int32> map(false); // This test uses new-style maps only.
|
| + const int kTestSize = 250000;
|
| + // Create a random-looking map of size n. Use non-negative integer keys.
|
| + uint32 frog = 123983;
|
| + int last_key = 0;
|
| + int counter = 0;
|
| + while (map.size() < kTestSize) {
|
| + frog *= static_cast<uint32>(k0);
|
| + frog ^= frog >> 17;
|
| + frog += counter++;
|
| + last_key =
|
| + static_cast<int>(frog) >= 0 ? static_cast<int>(frog) : last_key ^ 1;
|
| + GOOGLE_DCHECK_GE(last_key, 0);
|
| + map[last_key] = last_key ^ 1;
|
| + }
|
| + 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.
|
| + const int kChunkSize = 1000;
|
| + GOOGLE_CHECK_EQ(kTestSize % kChunkSize, 0);
|
| + do {
|
| + const int64 start = Now();
|
| + for (int i = 0; i < kChunkSize; i++) {
|
| + map.erase(map.begin());
|
| + }
|
| + const int64 end = Now();
|
| + if (end > start) {
|
| + times.push_back(end - start);
|
| + }
|
| + } while (!map.empty());
|
| + if (times.size() < .99 * kTestSize / kChunkSize) {
|
| + GOOGLE_LOG(WARNING) << "Now() isn't helping us measure time";
|
| + return;
|
| + }
|
| + int64 x0 = median(times.begin(), times.begin() + 9);
|
| + int64 x1 = median(times.begin() + times.size() - 9, times.end());
|
| + GOOGLE_LOG(INFO) << "x0=" << x0 << ", x1=" << x1;
|
| + // x1 will greatly exceed x0 if the code we just executed took O(n^2) time.
|
| + // And we'll probably time out and never get here. So, this test is
|
| + // intentionally loose: we check that x0 and x1 are within a factor of 8.
|
| + EXPECT_GE(x1, x0 / 8);
|
| + EXPECT_GE(x0, x1 / 8);
|
| +}
|
| +
|
| +// Try to create kTestSize keys that will land in just a few buckets, and
|
| +// time the insertions, to get a rough estimate of whether an O(n^2) worst case
|
| +// was triggered. This test is a hacky, but probably better than nothing.
|
| +TEST_P(MapImplTest, HashFlood) {
|
| + const int kTestSize = 1024; // must be a power of 2
|
| + std::set<int> s;
|
| + for (int i = 0; s.size() < kTestSize; i++) {
|
| + if ((map_.hash_function()(i) & (kTestSize - 1)) < 3) {
|
| + s.insert(i);
|
| + }
|
| + }
|
| + // Create hash table with kTestSize entries that hash flood a table with
|
| + // 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::set<int>::iterator it = s.begin();
|
| + int count = 0;
|
| + do {
|
| + const int64 start = Now();
|
| + map_[*it] = 0;
|
| + const int64 end = Now();
|
| + if (end > start) {
|
| + times.push_back(end - start);
|
| + }
|
| + ++count;
|
| + ++it;
|
| + } while (it != s.end());
|
| + if (times.size() < .99 * count) return;
|
| + int64 x0 = median(times.begin(), times.begin() + 9);
|
| + int64 x1 = median(times.begin() + times.size() - 9, times.end());
|
| + // x1 will greatly exceed x0 if the code we just executed took O(n^2) time.
|
| + // But we want to allow O(n log n). A factor of 20 should be generous enough.
|
| + EXPECT_LE(x1, x0 * 20);
|
| +}
|
| +
|
| +template <typename T, typename U>
|
| +static void TestValidityForAllKeysExcept(int key_to_avoid,
|
| + const T& check_map,
|
| + const U& map) {
|
| + typedef typename U::value_type value_type; // a key-value pair
|
| + for (typename U::const_iterator it = map.begin(); it != map.end(); ++it) {
|
| + const int key = it->first;
|
| + if (key == key_to_avoid) continue;
|
| + // All iterators relevant to this key, whether old (from check_map) or new,
|
| + // must point to the same memory. So, test pointer equality here.
|
| + const value_type* check_val = &*check_map.find(key)->second;
|
| + EXPECT_EQ(check_val, &*it);
|
| + EXPECT_EQ(check_val, &*map.find(key));
|
| + }
|
| +}
|
| +
|
| +// EXPECT i0 and i1 to be the same. Advancing them should have the same effect,
|
| +// too.
|
| +template <typename Iter>
|
| +static void TestEqualIterators(Iter i0, Iter i1, Iter end) {
|
| + const int kMaxAdvance = 10;
|
| + for (int i = 0; i < kMaxAdvance; i++) {
|
| + EXPECT_EQ(i0 == end, i1 == end);
|
| + if (i0 == end) return;
|
| + EXPECT_EQ(&*i0, &*i1) << "iter " << i;
|
| + ++i0;
|
| + ++i1;
|
| + }
|
| +}
|
| +
|
| +template <typename IteratorType>
|
| +static void TestOldVersusNewIterator(int skip, Map<int, int>* m) {
|
| + const int initial_size = m->size();
|
| + IteratorType it = m->begin();
|
| + for (int i = 0; i < skip && it != m->end(); it++, i++) {}
|
| + if (it == m->end()) return;
|
| + const IteratorType old = it;
|
| + GOOGLE_LOG(INFO) << "skip=" << skip << ", old->first=" << old->first;
|
| + const int target_size =
|
| + initial_size < 100 ? initial_size * 5 : initial_size * 5 / 4;
|
| + for (int i = 0; m->size() <= target_size; i++) {
|
| + (*m)[i] = 0;
|
| + }
|
| + // Iterator 'old' should still work just fine despite the growth of *m.
|
| + const IteratorType after_growth = m->find(old->first);
|
| + TestEqualIterators<IteratorType>(old, after_growth, m->end());
|
| +
|
| + // Now shrink the number of elements. Do this with a mix of erases and
|
| + // inserts to increase the chance that the hashtable will resize to a lower
|
| + // number of buckets. (But, in any case, the test is still useful.)
|
| + for (int i = 0; i < 2 * (target_size - initial_size); i++) {
|
| + if (i != old->first) {
|
| + m->erase(i);
|
| + }
|
| + if (((i ^ m->begin()->first) & 15) == 0) {
|
| + (*m)[i * 342] = i;
|
| + }
|
| + }
|
| + // Now, the table has grown and shrunk; test again.
|
| + TestEqualIterators<IteratorType>(old, m->find(old->first), m->end());
|
| + TestEqualIterators<IteratorType>(old, after_growth, m->end());
|
| +}
|
| +
|
| +// Create and test an n-element Map, with emphasis on iterator correctness.
|
| +static void StressTestIterators(int n, bool test_old_style_proto2_maps) {
|
| + GOOGLE_LOG(INFO) << "StressTestIterators " << n;
|
| + GOOGLE_CHECK_GT(n, 0);
|
| + // Create a random-looking map of size n. Use non-negative integer keys.
|
| + Map<int, int> m(test_old_style_proto2_maps);
|
| + uint32 frog = 123987 + n;
|
| + int last_key = 0;
|
| + int counter = 0;
|
| + while (m.size() < n) {
|
| + frog *= static_cast<uint32>(k0);
|
| + frog ^= frog >> 17;
|
| + frog += counter++;
|
| + last_key =
|
| + static_cast<int>(frog) >= 0 ? static_cast<int>(frog) : last_key ^ 1;
|
| + GOOGLE_DCHECK_GE(last_key, 0);
|
| + m[last_key] = last_key ^ 1;
|
| + }
|
| + // Test it.
|
| + ASSERT_EQ(n, m.size());
|
| + // Create maps of pointers and iterators.
|
| + // These should remain valid even if we modify m.
|
| + hash_map<int, Map<int, int>::value_type*> mp(n);
|
| + hash_map<int, Map<int, int>::iterator> mi(n);
|
| + for (Map<int, int>::iterator it = m.begin(); it != m.end(); ++it) {
|
| + mp[it->first] = &*it;
|
| + mi[it->first] = it;
|
| + }
|
| + ASSERT_EQ(m.size(), mi.size());
|
| + ASSERT_EQ(m.size(), mp.size());
|
| + m.erase(last_key);
|
| + ASSERT_EQ(n - 1, m.size());
|
| + TestValidityForAllKeysExcept(last_key, mp, m);
|
| + TestValidityForAllKeysExcept(last_key, mi, m);
|
| +
|
| + m[last_key] = 0;
|
| + ASSERT_EQ(n, m.size());
|
| + // 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
|
| + // what its documentation says.
|
| + m[last_key] = m[last_key ^ 999] = 0;
|
| + 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) {
|
| + if (it->first == last_key) {
|
| + position_of_last_key = v.size();
|
| + }
|
| + v.push_back(it);
|
| + }
|
| + ASSERT_EQ(m.size(), v.size());
|
| + const Map<int, int>::iterator erase_result = m.erase(m.find(last_key));
|
| + int index = 0;
|
| + for (Map<int, int>::iterator it = m.begin(); it != m.end(); ++it, ++index) {
|
| + if (index == position_of_last_key) {
|
| + EXPECT_EQ(&*erase_result, &*v[++index]);
|
| + }
|
| + ASSERT_EQ(&*it, &*v[index]);
|
| + }
|
| +}
|
| +
|
| +TEST_P(MapImplTest, IteratorInvalidation) {
|
| + // As multiple underlying hash_map implementations do not follow the
|
| + // validation requirement, the test is disabled for old-style maps.
|
| + if (GetParam()) return;
|
| + // Create a set of pseudo-random sizes to test.
|
| +#ifndef NDEBUG
|
| + const int kMaxSizeToTest = 100 * 1000;
|
| +#else
|
| + const int kMaxSizeToTest = 1000 * 1000;
|
| +#endif
|
| + std::set<int> s;
|
| + int n = kMaxSizeToTest;
|
| + int frog = k1 + n;
|
| + while (n > 1 && s.size() < 25) {
|
| + s.insert(n);
|
| + n = static_cast<int>(n * 100 / (101.0 + (frog & 63)));
|
| + frog *= k2;
|
| + frog ^= frog >> 17;
|
| + }
|
| + // Ensure we test a few small sizes.
|
| + s.insert(1);
|
| + s.insert(2);
|
| + s.insert(3);
|
| + // Now, the real work.
|
| + for (std::set<int>::iterator i = s.begin(); i != s.end(); ++i) {
|
| + StressTestIterators(*i, GetParam());
|
| + }
|
| +}
|
| +
|
| +// Test that erase() revalidates iterators.
|
| +TEST_P(MapImplTest, EraseRevalidates) {
|
| + // As multiple underlying hash_map implementations do not follow the
|
| + // validation requirement, the test is disabled for old-style maps.
|
| + if (GetParam()) return;
|
| + map_[3] = map_[13] = map_[20] = 0;
|
| + const int initial_size = map_.size();
|
| + EXPECT_EQ(3, initial_size);
|
| + vector<Map<int, int>::iterator> v;
|
| + for (Map<int, int>::iterator it = map_.begin(); it != map_.end(); ++it) {
|
| + v.push_back(it);
|
| + }
|
| + EXPECT_EQ(initial_size, v.size());
|
| + for (int i = 0; map_.size() <= initial_size * 20; i++) {
|
| + map_[i] = 0;
|
| + }
|
| + const int larger_size = map_.size();
|
| + // We've greatly increased the size of the map, so it is highly likely that
|
| + // the following will corrupt m if erase() doesn't properly revalidate
|
| + // iterators passed to it. Finishing this routine without crashing indicates
|
| + // success.
|
| + for (int i = 0; i < v.size(); i++) {
|
| + map_.erase(v[i]);
|
| + }
|
| + EXPECT_EQ(larger_size - v.size(), map_.size());
|
| +}
|
| +
|
| template <typename T>
|
| bool IsConstHelper(T& /*t*/) { // NOLINT. We want to catch non-const refs here.
|
| return false;
|
| @@ -290,7 +590,7 @@ bool IsConstHelper(const T& /*t*/) {
|
| return true;
|
| }
|
|
|
| -TEST_F(MapImplTest, IteratorConstness) {
|
| +TEST_P(MapImplTest, IteratorConstness) {
|
| map_[0] = 0;
|
| EXPECT_TRUE(IsConstHelper(*map_.cbegin()));
|
| EXPECT_TRUE(IsConstHelper(*const_map_.begin()));
|
| @@ -303,14 +603,14 @@ bool IsForwardIteratorHelper(T /*t*/) {
|
| return false;
|
| }
|
|
|
| -TEST_F(MapImplTest, IteratorCategory) {
|
| +TEST_P(MapImplTest, IteratorCategory) {
|
| EXPECT_TRUE(IsForwardIteratorHelper(
|
| std::iterator_traits<Map<int, int>::iterator>::iterator_category()));
|
| EXPECT_TRUE(IsForwardIteratorHelper(std::iterator_traits<
|
| Map<int, int>::const_iterator>::iterator_category()));
|
| }
|
|
|
| -TEST_F(MapImplTest, InsertSingle) {
|
| +TEST_P(MapImplTest, InsertSingle) {
|
| int32 key = 0;
|
| int32 value1 = 100;
|
| int32 value2 = 101;
|
| @@ -335,7 +635,7 @@ TEST_F(MapImplTest, InsertSingle) {
|
| EXPECT_FALSE(result2.second);
|
| }
|
|
|
| -TEST_F(MapImplTest, InsertByIterator) {
|
| +TEST_P(MapImplTest, InsertByIterator) {
|
| int32 key1 = 0;
|
| int32 key2 = 1;
|
| int32 value1a = 100;
|
| @@ -358,7 +658,7 @@ TEST_F(MapImplTest, InsertByIterator) {
|
| ExpectElements(map1);
|
| }
|
|
|
| -TEST_F(MapImplTest, EraseSingleByKey) {
|
| +TEST_P(MapImplTest, EraseSingleByKey) {
|
| int32 key = 0;
|
| int32 value = 100;
|
|
|
| @@ -376,7 +676,7 @@ TEST_F(MapImplTest, EraseSingleByKey) {
|
| EXPECT_EQ(0, map_.erase(key));
|
| }
|
|
|
| -TEST_F(MapImplTest, EraseMutipleByKey) {
|
| +TEST_P(MapImplTest, EraseMutipleByKey) {
|
| // erase in one specific order to trigger corner cases
|
| for (int i = 0; i < 5; i++) {
|
| map_[i] = i;
|
| @@ -403,7 +703,7 @@ TEST_F(MapImplTest, EraseMutipleByKey) {
|
| EXPECT_TRUE(map_.end() == map_.find(2));
|
| }
|
|
|
| -TEST_F(MapImplTest, EraseSingleByIterator) {
|
| +TEST_P(MapImplTest, EraseSingleByIterator) {
|
| int32 key = 0;
|
| int32 value = 100;
|
|
|
| @@ -418,7 +718,7 @@ TEST_F(MapImplTest, EraseSingleByIterator) {
|
| EXPECT_TRUE(map_.begin() == map_.end());
|
| }
|
|
|
| -TEST_F(MapImplTest, ValidIteratorAfterErase) {
|
| +TEST_P(MapImplTest, ValidIteratorAfterErase) {
|
| for (int i = 0; i < 10; i++) {
|
| map_[i] = i;
|
| }
|
| @@ -438,7 +738,7 @@ TEST_F(MapImplTest, ValidIteratorAfterErase) {
|
| EXPECT_EQ(5, map_.size());
|
| }
|
|
|
| -TEST_F(MapImplTest, EraseByIterator) {
|
| +TEST_P(MapImplTest, EraseByIterator) {
|
| int32 key1 = 0;
|
| int32 key2 = 1;
|
| int32 value1 = 100;
|
| @@ -459,7 +759,7 @@ TEST_F(MapImplTest, EraseByIterator) {
|
| EXPECT_TRUE(map_.begin() == map_.end());
|
| }
|
|
|
| -TEST_F(MapImplTest, Clear) {
|
| +TEST_P(MapImplTest, Clear) {
|
| int32 key = 0;
|
| int32 value = 100;
|
|
|
| @@ -474,7 +774,7 @@ TEST_F(MapImplTest, Clear) {
|
| EXPECT_TRUE(map_.begin() == map_.end());
|
| }
|
|
|
| -TEST_F(MapImplTest, CopyConstructor) {
|
| +static void CopyConstructorHelper(Arena* arena, Map<int32, int32>* m) {
|
| int32 key1 = 0;
|
| int32 key2 = 1;
|
| int32 value1 = 100;
|
| @@ -484,16 +784,25 @@ TEST_F(MapImplTest, CopyConstructor) {
|
| map[key1] = value1;
|
| map[key2] = value2;
|
|
|
| - map_.insert(map.begin(), map.end());
|
| + m->insert(map.begin(), map.end());
|
|
|
| - Map<int32, int32> other(map_);
|
| + Map<int32, int32> other(*m);
|
|
|
| EXPECT_EQ(2, other.size());
|
| EXPECT_EQ(value1, other.at(key1));
|
| EXPECT_EQ(value2, other.at(key2));
|
| }
|
|
|
| -TEST_F(MapImplTest, IterConstructor) {
|
| +TEST_P(MapImplTest, CopyConstructorWithArena) {
|
| + Arena a;
|
| + CopyConstructorHelper(&a, &map_);
|
| +}
|
| +
|
| +TEST_P(MapImplTest, CopyConstructorWithoutArena) {
|
| + CopyConstructorHelper(NULL, &map_);
|
| +}
|
| +
|
| +TEST_P(MapImplTest, IterConstructor) {
|
| int32 key1 = 0;
|
| int32 key2 = 1;
|
| int32 value1 = 100;
|
| @@ -503,14 +812,15 @@ TEST_F(MapImplTest, IterConstructor) {
|
| map[key1] = value1;
|
| map[key2] = value2;
|
|
|
| - Map<int32, int32> new_map(map.begin(), map.end());
|
| + Map<int32, int32> new_map(map.begin(), map.end(),
|
| + GetParam());
|
|
|
| EXPECT_EQ(2, new_map.size());
|
| EXPECT_EQ(value1, new_map.at(key1));
|
| EXPECT_EQ(value2, new_map.at(key2));
|
| }
|
|
|
| -TEST_F(MapImplTest, Assigner) {
|
| +TEST_P(MapImplTest, Assigner) {
|
| int32 key1 = 0;
|
| int32 key2 = 1;
|
| int32 value1 = 100;
|
| @@ -522,7 +832,7 @@ TEST_F(MapImplTest, Assigner) {
|
|
|
| map_.insert(map.begin(), map.end());
|
|
|
| - Map<int32, int32> other;
|
| + Map<int32, int32> other(GetParam());
|
| int32 key_other = 123;
|
| int32 value_other = 321;
|
| other[key_other] = value_other;
|
| @@ -540,9 +850,16 @@ TEST_F(MapImplTest, Assigner) {
|
| EXPECT_EQ(2, other.size());
|
| EXPECT_EQ(value1, other.at(key1));
|
| EXPECT_EQ(value2, other.at(key2));
|
| +
|
| + // Try assignment to a map with a different choice of "style."
|
| + Map<int32, int32> m(!GetParam());
|
| + m = other;
|
| + EXPECT_EQ(2, m.size());
|
| + EXPECT_EQ(value1, m.at(key1));
|
| + EXPECT_EQ(value2, m.at(key2));
|
| }
|
|
|
| -TEST_F(MapImplTest, Rehash) {
|
| +TEST_P(MapImplTest, Rehash) {
|
| const int test_size = 50;
|
| std::map<int32, int32> reference_map;
|
| for (int i = 0; i < test_size; i++) {
|
| @@ -559,7 +876,7 @@ TEST_F(MapImplTest, Rehash) {
|
| EXPECT_TRUE(map_.empty());
|
| }
|
|
|
| -TEST_F(MapImplTest, EqualRange) {
|
| +TEST_P(MapImplTest, EqualRange) {
|
| int key = 100, key_missing = 101;
|
| map_[key] = 100;
|
|
|
| @@ -583,14 +900,14 @@ TEST_F(MapImplTest, EqualRange) {
|
| EXPECT_TRUE(const_map_.end() == const_range.second);
|
| }
|
|
|
| -TEST_F(MapImplTest, ConvertToStdMap) {
|
| +TEST_P(MapImplTest, ConvertToStdMap) {
|
| map_[100] = 101;
|
| std::map<int32, int32> std_map(map_.begin(), map_.end());
|
| EXPECT_EQ(1, std_map.size());
|
| EXPECT_EQ(101, std_map[100]);
|
| }
|
|
|
| -TEST_F(MapImplTest, ConvertToStdVectorOfPairs) {
|
| +TEST_P(MapImplTest, ConvertToStdVectorOfPairs) {
|
| map_[100] = 101;
|
| std::vector<std::pair<int32, int32> > std_vec(map_.begin(), map_.end());
|
| EXPECT_EQ(1, std_vec.size());
|
| @@ -598,6 +915,8 @@ TEST_F(MapImplTest, ConvertToStdVectorOfPairs) {
|
| EXPECT_EQ(101, std_vec[0].second);
|
| }
|
|
|
| +INSTANTIATE_TEST_CASE_P(BoolSequence, MapImplTest, testing::Bool());
|
| +
|
| // Map Field Reflection Test ========================================
|
|
|
| static int Func(int i, int j) {
|
|
|