// 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/threading/sequence_local_storage_map.h"
|
|
#include <memory>
|
#include <utility>
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
namespace base {
|
namespace internal {
|
|
namespace {
|
|
constexpr int kSlotId = 1;
|
|
class SetOnDestroy {
|
public:
|
SetOnDestroy(bool* was_destroyed_ptr)
|
: was_destroyed_ptr_(was_destroyed_ptr) {
|
DCHECK(was_destroyed_ptr_);
|
DCHECK(!(*was_destroyed_ptr_));
|
}
|
~SetOnDestroy() {
|
DCHECK(!(*was_destroyed_ptr_));
|
*was_destroyed_ptr_ = true;
|
}
|
|
private:
|
bool* const was_destroyed_ptr_;
|
|
DISALLOW_COPY_AND_ASSIGN(SetOnDestroy);
|
};
|
|
template <typename T, typename... Args>
|
SequenceLocalStorageMap::ValueDestructorPair CreateValueDestructorPair(
|
Args... args) {
|
T* value = new T(args...);
|
SequenceLocalStorageMap::ValueDestructorPair::DestructorFunc* destructor =
|
[](void* ptr) { std::default_delete<T>()(static_cast<T*>(ptr)); };
|
|
SequenceLocalStorageMap::ValueDestructorPair value_destructor_pair{
|
value, destructor};
|
|
return value_destructor_pair;
|
}
|
|
} // namespace
|
|
// Verify that setting a value in the SequenceLocalStorageMap, then getting
|
// it will yield the same value.
|
TEST(SequenceLocalStorageMapTest, SetGet) {
|
SequenceLocalStorageMap sequence_local_storage_map;
|
ScopedSetSequenceLocalStorageMapForCurrentThread
|
scoped_sequence_local_storage_map(&sequence_local_storage_map);
|
|
SequenceLocalStorageMap::ValueDestructorPair value_destructor_pair =
|
CreateValueDestructorPair<int>(5);
|
|
sequence_local_storage_map.Set(kSlotId, std::move(value_destructor_pair));
|
|
EXPECT_EQ(*static_cast<int*>(sequence_local_storage_map.Get(kSlotId)), 5);
|
}
|
|
// Verify that the destructor is called on a value stored in the
|
// SequenceLocalStorageMap when SequenceLocalStorageMap is destroyed.
|
TEST(SequenceLocalStorageMapTest, Destructor) {
|
bool set_on_destruction = false;
|
|
{
|
SequenceLocalStorageMap sequence_local_storage_map;
|
ScopedSetSequenceLocalStorageMapForCurrentThread
|
scoped_sequence_local_storage_map(&sequence_local_storage_map);
|
|
SequenceLocalStorageMap::ValueDestructorPair value_destructor_pair =
|
CreateValueDestructorPair<SetOnDestroy>(&set_on_destruction);
|
|
sequence_local_storage_map.Set(kSlotId, std::move(value_destructor_pair));
|
}
|
|
EXPECT_TRUE(set_on_destruction);
|
}
|
|
// Verify that overwriting a value already in the SequenceLocalStorageMap
|
// calls value's destructor.
|
TEST(SequenceLocalStorageMapTest, DestructorCalledOnSetOverwrite) {
|
bool set_on_destruction = false;
|
bool set_on_destruction2 = false;
|
{
|
SequenceLocalStorageMap sequence_local_storage_map;
|
ScopedSetSequenceLocalStorageMapForCurrentThread
|
scoped_sequence_local_storage_map(&sequence_local_storage_map);
|
|
SequenceLocalStorageMap::ValueDestructorPair value_destructor_pair =
|
CreateValueDestructorPair<SetOnDestroy>(&set_on_destruction);
|
SequenceLocalStorageMap::ValueDestructorPair value_destructor_pair2 =
|
CreateValueDestructorPair<SetOnDestroy>(&set_on_destruction2);
|
|
sequence_local_storage_map.Set(kSlotId, std::move(value_destructor_pair));
|
|
ASSERT_FALSE(set_on_destruction);
|
|
// Overwrites the old value in the slot.
|
sequence_local_storage_map.Set(kSlotId, std::move(value_destructor_pair2));
|
|
// Destructor should've been called for the old value in the slot, and not
|
// yet called for the new value.
|
EXPECT_TRUE(set_on_destruction);
|
EXPECT_FALSE(set_on_destruction2);
|
}
|
EXPECT_TRUE(set_on_destruction2);
|
}
|
|
} // namespace internal
|
} // namespace base
|