// Copyright 2017 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/value_iterators.h" #include #include "base/memory/ptr_util.h" #include "base/values.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" namespace base { namespace detail { namespace { // Implementation of std::equal variant that is missing in C++11. template bool are_equal(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, BinaryPredicate pred) { for (; first1 != last1 && first2 != last2; ++first1, ++first2) { if (!pred(*first1, *first2)) return false; } return first1 == last1 && first2 == last2; } } // namespace TEST(ValueIteratorsTest, SameDictStorage) { static_assert(std::is_same::value, "DictStorage differs between Value and Value Iterators."); } TEST(ValueIteratorsTest, IsAssignable) { static_assert( !std::is_assignable(), "Can assign strings to dict_iterator"); static_assert( std::is_assignable(), "Can't assign Values to dict_iterator"); static_assert(!std::is_assignable(), "Can assign strings to const_dict_iterator"); static_assert( !std::is_assignable(), "Can assign Values to const_dict_iterator"); } TEST(ValueIteratorsTest, DictIteratorOperatorStar) { DictStorage storage; storage.emplace("0", std::make_unique(0)); using iterator = dict_iterator; iterator iter(storage.begin()); EXPECT_EQ("0", (*iter).first); EXPECT_EQ(Value(0), (*iter).second); (*iter).second = Value(1); EXPECT_EQ(Value(1), *storage["0"]); } TEST(ValueIteratorsTest, DictIteratorOperatorArrow) { DictStorage storage; storage.emplace("0", std::make_unique(0)); using iterator = dict_iterator; iterator iter(storage.begin()); EXPECT_EQ("0", iter->first); EXPECT_EQ(Value(0), iter->second); iter->second = Value(1); EXPECT_EQ(Value(1), *storage["0"]); } TEST(ValueIteratorsTest, DictIteratorPreIncrement) { DictStorage storage; storage.emplace("0", std::make_unique(0)); storage.emplace("1", std::make_unique(1)); using iterator = dict_iterator; iterator iter(storage.begin()); EXPECT_EQ("0", iter->first); EXPECT_EQ(Value(0), iter->second); iterator& iter_ref = ++iter; EXPECT_EQ(&iter, &iter_ref); EXPECT_EQ("1", iter_ref->first); EXPECT_EQ(Value(1), iter_ref->second); } TEST(ValueIteratorsTest, DictIteratorPostIncrement) { DictStorage storage; storage.emplace("0", std::make_unique(0)); storage.emplace("1", std::make_unique(1)); using iterator = dict_iterator; iterator iter(storage.begin()); iterator iter_old = iter++; EXPECT_EQ("0", iter_old->first); EXPECT_EQ(Value(0), iter_old->second); EXPECT_EQ("1", iter->first); EXPECT_EQ(Value(1), iter->second); } TEST(ValueIteratorsTest, DictIteratorPreDecrement) { DictStorage storage; storage.emplace("0", std::make_unique(0)); storage.emplace("1", std::make_unique(1)); using iterator = dict_iterator; iterator iter(++storage.begin()); EXPECT_EQ("1", iter->first); EXPECT_EQ(Value(1), iter->second); iterator& iter_ref = --iter; EXPECT_EQ(&iter, &iter_ref); EXPECT_EQ("0", iter_ref->first); EXPECT_EQ(Value(0), iter_ref->second); } TEST(ValueIteratorsTest, DictIteratorPostDecrement) { DictStorage storage; storage.emplace("0", std::make_unique(0)); storage.emplace("1", std::make_unique(1)); using iterator = dict_iterator; iterator iter(++storage.begin()); iterator iter_old = iter--; EXPECT_EQ("1", iter_old->first); EXPECT_EQ(Value(1), iter_old->second); EXPECT_EQ("0", iter->first); EXPECT_EQ(Value(0), iter->second); } TEST(ValueIteratorsTest, DictIteratorOperatorEQ) { DictStorage storage; using iterator = dict_iterator; EXPECT_EQ(iterator(storage.begin()), iterator(storage.begin())); EXPECT_EQ(iterator(storage.end()), iterator(storage.end())); } TEST(ValueIteratorsTest, DictIteratorOperatorNE) { DictStorage storage; storage.emplace("0", std::make_unique(0)); using iterator = dict_iterator; EXPECT_NE(iterator(storage.begin()), iterator(storage.end())); } TEST(ValueIteratorsTest, ConstDictIteratorOperatorStar) { DictStorage storage; storage.emplace("0", std::make_unique(0)); using iterator = const_dict_iterator; iterator iter(storage.begin()); EXPECT_EQ("0", (*iter).first); EXPECT_EQ(Value(0), (*iter).second); } TEST(ValueIteratorsTest, ConstDictIteratorOperatorArrow) { DictStorage storage; storage.emplace("0", std::make_unique(0)); using iterator = const_dict_iterator; iterator iter(storage.begin()); EXPECT_EQ("0", iter->first); EXPECT_EQ(Value(0), iter->second); } TEST(ValueIteratorsTest, ConstDictIteratorPreIncrement) { DictStorage storage; storage.emplace("0", std::make_unique(0)); storage.emplace("1", std::make_unique(1)); using iterator = const_dict_iterator; iterator iter(storage.begin()); EXPECT_EQ("0", iter->first); EXPECT_EQ(Value(0), iter->second); iterator& iter_ref = ++iter; EXPECT_EQ(&iter, &iter_ref); EXPECT_EQ("1", iter_ref->first); EXPECT_EQ(Value(1), iter_ref->second); } TEST(ValueIteratorsTest, ConstDictIteratorPostIncrement) { DictStorage storage; storage.emplace("0", std::make_unique(0)); storage.emplace("1", std::make_unique(1)); using iterator = const_dict_iterator; iterator iter(storage.begin()); iterator iter_old = iter++; EXPECT_EQ("0", iter_old->first); EXPECT_EQ(Value(0), iter_old->second); EXPECT_EQ("1", iter->first); EXPECT_EQ(Value(1), iter->second); } TEST(ValueIteratorsTest, ConstDictIteratorPreDecrement) { DictStorage storage; storage.emplace("0", std::make_unique(0)); storage.emplace("1", std::make_unique(1)); using iterator = const_dict_iterator; iterator iter(++storage.begin()); EXPECT_EQ("1", iter->first); EXPECT_EQ(Value(1), iter->second); iterator& iter_ref = --iter; EXPECT_EQ(&iter, &iter_ref); EXPECT_EQ("0", iter_ref->first); EXPECT_EQ(Value(0), iter_ref->second); } TEST(ValueIteratorsTest, ConstDictIteratorPostDecrement) { DictStorage storage; storage.emplace("0", std::make_unique(0)); storage.emplace("1", std::make_unique(1)); using iterator = const_dict_iterator; iterator iter(++storage.begin()); iterator iter_old = iter--; EXPECT_EQ("1", iter_old->first); EXPECT_EQ(Value(1), iter_old->second); EXPECT_EQ("0", iter->first); EXPECT_EQ(Value(0), iter->second); } TEST(ValueIteratorsTest, ConstDictIteratorOperatorEQ) { DictStorage storage; using iterator = const_dict_iterator; EXPECT_EQ(iterator(storage.begin()), iterator(storage.begin())); EXPECT_EQ(iterator(storage.end()), iterator(storage.end())); } TEST(ValueIteratorsTest, ConstDictIteratorOperatorNE) { DictStorage storage; storage.emplace("0", std::make_unique(0)); using iterator = const_dict_iterator; EXPECT_NE(iterator(storage.begin()), iterator(storage.end())); } TEST(ValueIteratorsTest, DictIteratorProxy) { DictStorage storage; storage.emplace("null", std::make_unique(Value::Type::NONE)); storage.emplace("bool", std::make_unique(Value::Type::BOOLEAN)); storage.emplace("int", std::make_unique(Value::Type::INTEGER)); storage.emplace("double", std::make_unique(Value::Type::DOUBLE)); storage.emplace("string", std::make_unique(Value::Type::STRING)); storage.emplace("blob", std::make_unique(Value::Type::BINARY)); storage.emplace("dict", std::make_unique(Value::Type::DICTIONARY)); storage.emplace("list", std::make_unique(Value::Type::LIST)); using iterator = const_dict_iterator; using iterator_proxy = dict_iterator_proxy; iterator_proxy proxy(&storage); auto equal_to = [](const DictStorage::value_type& lhs, const iterator::reference& rhs) { return std::tie(lhs.first, *lhs.second) == std::tie(rhs.first, rhs.second); }; EXPECT_TRUE(are_equal(storage.begin(), storage.end(), proxy.begin(), proxy.end(), equal_to)); EXPECT_TRUE(are_equal(storage.rbegin(), storage.rend(), proxy.rbegin(), proxy.rend(), equal_to)); EXPECT_TRUE(are_equal(storage.cbegin(), storage.cend(), proxy.cbegin(), proxy.cend(), equal_to)); EXPECT_TRUE(are_equal(storage.crbegin(), storage.crend(), proxy.crbegin(), proxy.crend(), equal_to)); } TEST(ValueIteratorsTest, ConstDictIteratorProxy) { DictStorage storage; storage.emplace("null", std::make_unique(Value::Type::NONE)); storage.emplace("bool", std::make_unique(Value::Type::BOOLEAN)); storage.emplace("int", std::make_unique(Value::Type::INTEGER)); storage.emplace("double", std::make_unique(Value::Type::DOUBLE)); storage.emplace("string", std::make_unique(Value::Type::STRING)); storage.emplace("blob", std::make_unique(Value::Type::BINARY)); storage.emplace("dict", std::make_unique(Value::Type::DICTIONARY)); storage.emplace("list", std::make_unique(Value::Type::LIST)); using iterator = const_dict_iterator; using iterator_proxy = const_dict_iterator_proxy; iterator_proxy proxy(&storage); auto equal_to = [](const DictStorage::value_type& lhs, const iterator::reference& rhs) { return std::tie(lhs.first, *lhs.second) == std::tie(rhs.first, rhs.second); }; EXPECT_TRUE(are_equal(storage.begin(), storage.end(), proxy.begin(), proxy.end(), equal_to)); EXPECT_TRUE(are_equal(storage.rbegin(), storage.rend(), proxy.rbegin(), proxy.rend(), equal_to)); EXPECT_TRUE(are_equal(storage.cbegin(), storage.cend(), proxy.cbegin(), proxy.cend(), equal_to)); EXPECT_TRUE(are_equal(storage.crbegin(), storage.crend(), proxy.crbegin(), proxy.crend(), equal_to)); } } // namespace detail } // namespace base