| // 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_slot.h" |
| |
| #include <utility> |
| |
| #include "base/macros.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/threading/sequence_local_storage_map.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace base { |
| |
| namespace { |
| |
| class SequenceLocalStorageSlotTest : public testing::Test { |
| protected: |
| SequenceLocalStorageSlotTest() |
| : scoped_sequence_local_storage_(&sequence_local_storage_) {} |
| |
| internal::SequenceLocalStorageMap sequence_local_storage_; |
| internal::ScopedSetSequenceLocalStorageMapForCurrentThread |
| scoped_sequence_local_storage_; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(SequenceLocalStorageSlotTest); |
| }; |
| |
| } // namespace |
| |
| // Verify that a value stored with Set() can be retrieved with Get(). |
| TEST_F(SequenceLocalStorageSlotTest, GetSet) { |
| SequenceLocalStorageSlot<int> slot; |
| slot.Set(5); |
| EXPECT_EQ(slot.Get(), 5); |
| } |
| |
| // Verify that setting an object in a SequenceLocalStorageSlot creates a copy |
| // of that object independent of the original one. |
| TEST_F(SequenceLocalStorageSlotTest, SetObjectIsIndependent) { |
| bool should_be_false = false; |
| |
| SequenceLocalStorageSlot<bool> slot; |
| |
| slot.Set(should_be_false); |
| |
| EXPECT_FALSE(slot.Get()); |
| slot.Get() = true; |
| EXPECT_TRUE(slot.Get()); |
| |
| EXPECT_NE(should_be_false, slot.Get()); |
| } |
| |
| // Verify that multiple slots work and that calling Get after overwriting |
| // a value in a slot yields the new value. |
| TEST_F(SequenceLocalStorageSlotTest, GetSetMultipleSlots) { |
| SequenceLocalStorageSlot<int> slot1; |
| SequenceLocalStorageSlot<int> slot2; |
| SequenceLocalStorageSlot<int> slot3; |
| |
| slot1.Set(1); |
| slot2.Set(2); |
| slot3.Set(3); |
| |
| EXPECT_EQ(slot1.Get(), 1); |
| EXPECT_EQ(slot2.Get(), 2); |
| EXPECT_EQ(slot3.Get(), 3); |
| |
| slot3.Set(4); |
| slot2.Set(5); |
| slot1.Set(6); |
| |
| EXPECT_EQ(slot3.Get(), 4); |
| EXPECT_EQ(slot2.Get(), 5); |
| EXPECT_EQ(slot1.Get(), 6); |
| } |
| |
| // Verify that changing the the value returned by Get() changes the value |
| // in sequence local storage. |
| TEST_F(SequenceLocalStorageSlotTest, GetReferenceModifiable) { |
| SequenceLocalStorageSlot<bool> slot; |
| slot.Set(false); |
| slot.Get() = true; |
| EXPECT_TRUE(slot.Get()); |
| } |
| |
| // Verify that a move-only type can be stored in sequence local storage. |
| TEST_F(SequenceLocalStorageSlotTest, SetGetWithMoveOnlyType) { |
| std::unique_ptr<int> int_unique_ptr = std::make_unique<int>(5); |
| |
| SequenceLocalStorageSlot<std::unique_ptr<int>> slot; |
| slot.Set(std::move(int_unique_ptr)); |
| |
| EXPECT_EQ(*slot.Get(), 5); |
| } |
| |
| // Verify that a Get() without a previous Set() on a slot returns a |
| // default-constructed value. |
| TEST_F(SequenceLocalStorageSlotTest, GetWithoutSetDefaultConstructs) { |
| struct DefaultConstructable { |
| int x = 0x12345678; |
| }; |
| |
| SequenceLocalStorageSlot<DefaultConstructable> slot; |
| |
| EXPECT_EQ(slot.Get().x, 0x12345678); |
| } |
| |
| // Verify that a Get() without a previous Set() on a slot with a POD-type |
| // returns a default-constructed value. |
| // Note: this test could be flaky and give a false pass. If it's flaky, the test |
| // might've "passed" because the memory for the slot happened to be zeroed. |
| TEST_F(SequenceLocalStorageSlotTest, GetWithoutSetDefaultConstructsPOD) { |
| SequenceLocalStorageSlot<void*> slot; |
| |
| EXPECT_EQ(slot.Get(), nullptr); |
| } |
| |
| // Verify that the value of a slot is specific to a SequenceLocalStorageMap |
| TEST(SequenceLocalStorageSlotMultipleMapTest, SetGetMultipleMapsOneSlot) { |
| SequenceLocalStorageSlot<unsigned int> slot; |
| internal::SequenceLocalStorageMap sequence_local_storage_maps[5]; |
| |
| // Set the value of the slot to be the index of the current |
| // SequenceLocalStorageMaps in the vector |
| for (unsigned int i = 0; i < arraysize(sequence_local_storage_maps); ++i) { |
| internal::ScopedSetSequenceLocalStorageMapForCurrentThread |
| scoped_sequence_local_storage(&sequence_local_storage_maps[i]); |
| |
| slot.Set(i); |
| } |
| |
| for (unsigned int i = 0; i < arraysize(sequence_local_storage_maps); ++i) { |
| internal::ScopedSetSequenceLocalStorageMapForCurrentThread |
| scoped_sequence_local_storage(&sequence_local_storage_maps[i]); |
| |
| EXPECT_EQ(slot.Get(), i); |
| } |
| } |
| |
| } // namespace base |