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