| // 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 |