blob: 086c4fe827113a2ef8f648d1a4012291a7be0891 [file] [log] [blame]
// Copyright 2015 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/containers/scoped_ptr_map.h"
#include <functional>
#include <map>
#include <utility>
#include "base/bind.h"
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
namespace {
namespace namespace_with_ignore_result {
class Value {};
template <typename T>
void ignore_result(const T&) {}
} // namespace namespace_with_ignore_result
// A ScopedDestroyer sets a Boolean to true upon destruction.
class ScopedDestroyer {
public:
ScopedDestroyer(bool* destroyed) : destroyed_(destroyed) {
*destroyed_ = false;
}
~ScopedDestroyer() { *destroyed_ = true; }
private:
bool* destroyed_;
};
TEST(ScopedPtrMapTest, Insert) {
bool destroyed1 = false;
bool destroyed2 = false;
{
ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
// Insert to new key.
ScopedDestroyer* elem1 = new ScopedDestroyer(&destroyed1);
EXPECT_FALSE(destroyed1);
EXPECT_TRUE(scoped_map.insert(0, make_scoped_ptr(elem1)).second);
EXPECT_EQ(elem1, scoped_map.find(0)->second);
EXPECT_FALSE(destroyed1);
// Insert to existing key.
ScopedDestroyer* elem2 = new ScopedDestroyer(&destroyed2);
EXPECT_FALSE(destroyed2);
EXPECT_FALSE(scoped_map.insert(0, make_scoped_ptr(elem2)).second);
EXPECT_EQ(elem1, scoped_map.find(0)->second);
EXPECT_FALSE(destroyed1);
EXPECT_TRUE(destroyed2);
}
EXPECT_TRUE(destroyed1);
}
TEST(ScopedPtrMapTest, Set) {
bool destroyed1 = false;
bool destroyed2 = false;
{
ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
// Set a new key.
ScopedDestroyer* elem1 = new ScopedDestroyer(&destroyed1);
EXPECT_FALSE(destroyed1);
scoped_map.set(0, make_scoped_ptr(elem1));
EXPECT_EQ(elem1, scoped_map.find(0)->second);
EXPECT_FALSE(destroyed1);
// Set to replace an existing key.
ScopedDestroyer* elem2 = new ScopedDestroyer(&destroyed2);
EXPECT_FALSE(destroyed2);
scoped_map.set(0, make_scoped_ptr(elem2));
EXPECT_EQ(elem2, scoped_map.find(0)->second);
EXPECT_TRUE(destroyed1);
EXPECT_FALSE(destroyed2);
}
EXPECT_TRUE(destroyed1);
EXPECT_TRUE(destroyed2);
}
TEST(ScopedPtrMapTest, EraseIterator) {
bool destroyed = false;
ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
scoped_map.insert(0, make_scoped_ptr(new ScopedDestroyer(&destroyed)));
EXPECT_FALSE(destroyed);
scoped_map.erase(scoped_map.find(0));
EXPECT_TRUE(destroyed);
EXPECT_TRUE(scoped_map.empty());
}
TEST(ScopedPtrMapTest, EraseKey) {
bool destroyed = false;
ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
scoped_map.insert(0, make_scoped_ptr(new ScopedDestroyer(&destroyed)));
EXPECT_FALSE(destroyed);
EXPECT_EQ(1u, scoped_map.erase(0));
EXPECT_TRUE(destroyed);
EXPECT_TRUE(scoped_map.empty());
// Test erase of a non-existent key.
EXPECT_EQ(0u, scoped_map.erase(7));
}
TEST(ScopedPtrMapTest, EraseRange) {
bool destroyed1 = false;
bool destroyed2 = false;
ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
scoped_map.insert(0, make_scoped_ptr(new ScopedDestroyer(&destroyed1)));
EXPECT_FALSE(destroyed1);
scoped_map.insert(1, make_scoped_ptr(new ScopedDestroyer(&destroyed2)));
EXPECT_FALSE(destroyed2);
scoped_map.erase(scoped_map.find(0), scoped_map.end());
EXPECT_TRUE(destroyed1);
EXPECT_TRUE(destroyed2);
EXPECT_TRUE(scoped_map.empty());
}
TEST(ScopedPtrMapTest, TakeAndErase) {
bool destroyed = false;
ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
ScopedDestroyer* elem = new ScopedDestroyer(&destroyed);
scoped_map.insert(0, make_scoped_ptr(elem));
EXPECT_EQ(elem, scoped_map.find(0)->second);
EXPECT_FALSE(destroyed);
scoped_ptr<ScopedDestroyer> object = scoped_map.take_and_erase(0);
EXPECT_EQ(elem, object.get());
EXPECT_FALSE(destroyed);
EXPECT_TRUE(scoped_map.empty());
object.reset();
EXPECT_TRUE(destroyed);
}
TEST(ScopedPtrMapTest, Clear) {
bool destroyed = false;
ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
scoped_map.insert(0, make_scoped_ptr(new ScopedDestroyer(&destroyed)));
EXPECT_FALSE(destroyed);
scoped_map.clear();
EXPECT_TRUE(destroyed);
EXPECT_TRUE(scoped_map.empty());
}
TEST(ScopedPtrMapTest, Compare) {
// Construct a ScopedPtrMap with a custom comparison function.
ScopedPtrMap<int, scoped_ptr<int>, std::greater<int>> scoped_map1;
scoped_map1.insert(0, make_scoped_ptr(new int(0)));
scoped_map1.insert(1, make_scoped_ptr(new int(0)));
auto it = scoped_map1.begin();
EXPECT_EQ(1, it->first);
++it;
EXPECT_EQ(0, it->first);
// Test the move constructor.
ScopedPtrMap<int, scoped_ptr<int>, std::greater<int>> scoped_map2(
scoped_map1.Pass());
EXPECT_EQ(2u, scoped_map2.size());
EXPECT_TRUE(scoped_map1.empty());
// Test move assignment.
scoped_map1 = scoped_map2.Pass();
EXPECT_EQ(2u, scoped_map1.size());
EXPECT_TRUE(scoped_map2.empty());
// Test swap.
scoped_map2.swap(scoped_map1);
EXPECT_EQ(2u, scoped_map2.size());
EXPECT_TRUE(scoped_map1.empty());
}
TEST(ScopedPtrMapTest, Scope) {
bool destroyed = false;
{
ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
scoped_map.insert(0, make_scoped_ptr(new ScopedDestroyer(&destroyed)));
EXPECT_FALSE(destroyed);
}
EXPECT_TRUE(destroyed);
}
TEST(ScopedPtrMapTest, MoveConstruct) {
bool destroyed = false;
{
ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
ScopedDestroyer* elem = new ScopedDestroyer(&destroyed);
scoped_map.insert(0, make_scoped_ptr(elem));
EXPECT_EQ(elem, scoped_map.find(0)->second);
EXPECT_FALSE(destroyed);
EXPECT_FALSE(scoped_map.empty());
ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map_copy(
scoped_map.Pass());
EXPECT_TRUE(scoped_map.empty());
EXPECT_FALSE(scoped_map_copy.empty());
EXPECT_EQ(elem, scoped_map_copy.find(0)->second);
EXPECT_FALSE(destroyed);
}
EXPECT_TRUE(destroyed);
}
TEST(ScopedPtrMapTest, MoveAssign) {
bool destroyed = false;
{
ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
ScopedDestroyer* elem = new ScopedDestroyer(&destroyed);
scoped_map.insert(0, make_scoped_ptr(elem));
EXPECT_EQ(elem, scoped_map.find(0)->second);
EXPECT_FALSE(destroyed);
EXPECT_FALSE(scoped_map.empty());
ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map_assign;
scoped_map_assign = scoped_map.Pass();
EXPECT_TRUE(scoped_map.empty());
EXPECT_FALSE(scoped_map_assign.empty());
EXPECT_EQ(elem, scoped_map_assign.find(0)->second);
EXPECT_FALSE(destroyed);
}
EXPECT_TRUE(destroyed);
}
template <typename Key, typename ScopedPtr>
ScopedPtrMap<Key, ScopedPtr> PassThru(ScopedPtrMap<Key, ScopedPtr> scoper) {
return scoper;
}
TEST(ScopedPtrMapTest, Passed) {
bool destroyed = false;
ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
ScopedDestroyer* elem = new ScopedDestroyer(&destroyed);
scoped_map.insert(0, make_scoped_ptr(elem));
EXPECT_EQ(elem, scoped_map.find(0)->second);
EXPECT_FALSE(destroyed);
base::Callback<ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>>(void)>
callback = base::Bind(&PassThru<int, scoped_ptr<ScopedDestroyer>>,
base::Passed(&scoped_map));
EXPECT_TRUE(scoped_map.empty());
EXPECT_FALSE(destroyed);
ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> result = callback.Run();
EXPECT_TRUE(scoped_map.empty());
EXPECT_EQ(elem, result.find(0)->second);
EXPECT_FALSE(destroyed);
result.clear();
EXPECT_TRUE(destroyed);
};
// Test that using a value type from a namespace containing an ignore_result
// function compiles correctly.
TEST(ScopedPtrMapTest, IgnoreResultCompile) {
ScopedPtrMap<int, scoped_ptr<namespace_with_ignore_result::Value>> scoped_map;
scoped_map.insert(1,
make_scoped_ptr(new namespace_with_ignore_result::Value));
}
} // namespace
} // namespace base