1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/threading/sequence_local_storage_slot.h"
6
7 #include <utility>
8
9 #include "base/macros.h"
10 #include "base/memory/ptr_util.h"
11 #include "base/threading/sequence_local_storage_map.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13
14 namespace base {
15
16 namespace {
17
18 class SequenceLocalStorageSlotTest : public testing::Test {
19 protected:
SequenceLocalStorageSlotTest()20 SequenceLocalStorageSlotTest()
21 : scoped_sequence_local_storage_(&sequence_local_storage_) {}
22
23 internal::SequenceLocalStorageMap sequence_local_storage_;
24 internal::ScopedSetSequenceLocalStorageMapForCurrentThread
25 scoped_sequence_local_storage_;
26
27 private:
28 DISALLOW_COPY_AND_ASSIGN(SequenceLocalStorageSlotTest);
29 };
30
31 } // namespace
32
33 // Verify that a value stored with Set() can be retrieved with Get().
TEST_F(SequenceLocalStorageSlotTest,GetSet)34 TEST_F(SequenceLocalStorageSlotTest, GetSet) {
35 SequenceLocalStorageSlot<int> slot;
36 slot.Set(5);
37 EXPECT_EQ(slot.Get(), 5);
38 }
39
40 // Verify that setting an object in a SequenceLocalStorageSlot creates a copy
41 // of that object independent of the original one.
TEST_F(SequenceLocalStorageSlotTest,SetObjectIsIndependent)42 TEST_F(SequenceLocalStorageSlotTest, SetObjectIsIndependent) {
43 bool should_be_false = false;
44
45 SequenceLocalStorageSlot<bool> slot;
46
47 slot.Set(should_be_false);
48
49 EXPECT_FALSE(slot.Get());
50 slot.Get() = true;
51 EXPECT_TRUE(slot.Get());
52
53 EXPECT_NE(should_be_false, slot.Get());
54 }
55
56 // Verify that multiple slots work and that calling Get after overwriting
57 // a value in a slot yields the new value.
TEST_F(SequenceLocalStorageSlotTest,GetSetMultipleSlots)58 TEST_F(SequenceLocalStorageSlotTest, GetSetMultipleSlots) {
59 SequenceLocalStorageSlot<int> slot1;
60 SequenceLocalStorageSlot<int> slot2;
61 SequenceLocalStorageSlot<int> slot3;
62
63 slot1.Set(1);
64 slot2.Set(2);
65 slot3.Set(3);
66
67 EXPECT_EQ(slot1.Get(), 1);
68 EXPECT_EQ(slot2.Get(), 2);
69 EXPECT_EQ(slot3.Get(), 3);
70
71 slot3.Set(4);
72 slot2.Set(5);
73 slot1.Set(6);
74
75 EXPECT_EQ(slot3.Get(), 4);
76 EXPECT_EQ(slot2.Get(), 5);
77 EXPECT_EQ(slot1.Get(), 6);
78 }
79
80 // Verify that changing the the value returned by Get() changes the value
81 // in sequence local storage.
TEST_F(SequenceLocalStorageSlotTest,GetReferenceModifiable)82 TEST_F(SequenceLocalStorageSlotTest, GetReferenceModifiable) {
83 SequenceLocalStorageSlot<bool> slot;
84 slot.Set(false);
85 slot.Get() = true;
86 EXPECT_TRUE(slot.Get());
87 }
88
89 // Verify that a move-only type can be stored in sequence local storage.
TEST_F(SequenceLocalStorageSlotTest,SetGetWithMoveOnlyType)90 TEST_F(SequenceLocalStorageSlotTest, SetGetWithMoveOnlyType) {
91 std::unique_ptr<int> int_unique_ptr = std::make_unique<int>(5);
92
93 SequenceLocalStorageSlot<std::unique_ptr<int>> slot;
94 slot.Set(std::move(int_unique_ptr));
95
96 EXPECT_EQ(*slot.Get(), 5);
97 }
98
99 // Verify that a Get() without a previous Set() on a slot returns a
100 // default-constructed value.
TEST_F(SequenceLocalStorageSlotTest,GetWithoutSetDefaultConstructs)101 TEST_F(SequenceLocalStorageSlotTest, GetWithoutSetDefaultConstructs) {
102 struct DefaultConstructable {
103 int x = 0x12345678;
104 };
105
106 SequenceLocalStorageSlot<DefaultConstructable> slot;
107
108 EXPECT_EQ(slot.Get().x, 0x12345678);
109 }
110
111 // Verify that a Get() without a previous Set() on a slot with a POD-type
112 // returns a default-constructed value.
113 // Note: this test could be flaky and give a false pass. If it's flaky, the test
114 // might've "passed" because the memory for the slot happened to be zeroed.
TEST_F(SequenceLocalStorageSlotTest,GetWithoutSetDefaultConstructsPOD)115 TEST_F(SequenceLocalStorageSlotTest, GetWithoutSetDefaultConstructsPOD) {
116 SequenceLocalStorageSlot<void*> slot;
117
118 EXPECT_EQ(slot.Get(), nullptr);
119 }
120
121 // Verify that the value of a slot is specific to a SequenceLocalStorageMap
TEST(SequenceLocalStorageSlotMultipleMapTest,SetGetMultipleMapsOneSlot)122 TEST(SequenceLocalStorageSlotMultipleMapTest, SetGetMultipleMapsOneSlot) {
123 SequenceLocalStorageSlot<unsigned int> slot;
124 internal::SequenceLocalStorageMap sequence_local_storage_maps[5];
125
126 // Set the value of the slot to be the index of the current
127 // SequenceLocalStorageMaps in the vector
128 for (unsigned int i = 0; i < arraysize(sequence_local_storage_maps); ++i) {
129 internal::ScopedSetSequenceLocalStorageMapForCurrentThread
130 scoped_sequence_local_storage(&sequence_local_storage_maps[i]);
131
132 slot.Set(i);
133 }
134
135 for (unsigned int i = 0; i < arraysize(sequence_local_storage_maps); ++i) {
136 internal::ScopedSetSequenceLocalStorageMapForCurrentThread
137 scoped_sequence_local_storage(&sequence_local_storage_maps[i]);
138
139 EXPECT_EQ(slot.Get(), i);
140 }
141 }
142
143 } // namespace base
144