1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
|
// Copyright 2017 The Chromium Authors
// 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 <array>
#include <utility>
#include "base/memory/ptr_util.h"
#include "base/threading/sequence_local_storage_map.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
namespace {
template <class T>
class SequenceLocalStorageSlotTest : public testing::Test {
public:
SequenceLocalStorageSlotTest(const SequenceLocalStorageSlotTest&) = delete;
SequenceLocalStorageSlotTest& operator=(const SequenceLocalStorageSlotTest&) =
delete;
protected:
SequenceLocalStorageSlotTest()
: scoped_sequence_local_storage_(&sequence_local_storage_) {}
internal::SequenceLocalStorageMap sequence_local_storage_;
internal::ScopedSetSequenceLocalStorageMapForCurrentThread
scoped_sequence_local_storage_;
};
} // namespace
struct GenericSLS {
template <class T>
using Type = GenericSequenceLocalStorageSlot<T>;
};
struct SmallSLS {
template <class T>
using Type = GenericSequenceLocalStorageSlot<T>;
};
using StorageTypes = testing::Types<GenericSLS, SmallSLS>;
TYPED_TEST_SUITE(SequenceLocalStorageSlotTest, StorageTypes);
// Verify that a value stored with emplace() can be retrieved with operator*().
TYPED_TEST(SequenceLocalStorageSlotTest, GetEmplace) {
using SLSType = typename TypeParam::template Type<int>;
SLSType slot;
slot.emplace(5);
EXPECT_EQ(*slot, 5);
}
// Verify that inserting an object in a SequenceLocalStorageSlot creates a copy
// of that object independent of the original one.
TYPED_TEST(SequenceLocalStorageSlotTest, EmplaceObjectIsIndependent) {
using SLSType = typename TypeParam::template Type<bool>;
bool should_be_false = false;
SLSType slot;
slot.emplace(should_be_false);
EXPECT_FALSE(*slot);
*slot = true;
EXPECT_TRUE(*slot);
EXPECT_NE(should_be_false, *slot);
}
// Verify that multiple slots work and that calling emplace after overwriting
// a value in a slot yields the new value.
TYPED_TEST(SequenceLocalStorageSlotTest, GetEmplaceMultipleSlots) {
using SLSType = typename TypeParam::template Type<int>;
SLSType slot1;
SLSType slot2;
SLSType slot3;
EXPECT_FALSE(slot1);
EXPECT_FALSE(slot2);
EXPECT_FALSE(slot3);
slot1.emplace(1);
slot2.emplace(2);
slot3.emplace(3);
EXPECT_TRUE(slot1);
EXPECT_TRUE(slot2);
EXPECT_TRUE(slot3);
EXPECT_EQ(*slot1, 1);
EXPECT_EQ(*slot2, 2);
EXPECT_EQ(*slot3, 3);
slot3.emplace(4);
slot2.emplace(5);
slot1.emplace(6);
EXPECT_EQ(*slot3, 4);
EXPECT_EQ(*slot2, 5);
EXPECT_EQ(*slot1, 6);
}
// Verify that changing the value returned by Get() changes the value
// in sequence local storage.
TYPED_TEST(SequenceLocalStorageSlotTest, GetReferenceModifiable) {
using SLSType = typename TypeParam::template Type<bool>;
SLSType slot;
slot.emplace(false);
*slot = true;
EXPECT_TRUE(*slot);
}
// Verify that a move-only type can be stored in sequence local storage.
TYPED_TEST(SequenceLocalStorageSlotTest, EmplaceGetWithMoveOnlyType) {
struct MoveOnly {
MoveOnly() = default;
MoveOnly(const MoveOnly&) = delete;
MoveOnly& operator=(const MoveOnly&) = delete;
MoveOnly(MoveOnly&&) = default;
MoveOnly& operator=(MoveOnly&&) = default;
int x = 0x12345678;
};
using SLSType = typename TypeParam::template Type<MoveOnly>;
MoveOnly move_only;
SLSType slot;
slot.emplace(std::move(move_only));
EXPECT_EQ(slot->x, 0x12345678);
}
// Verify that a Get() without a previous Set() on a slot returns a
// default-constructed value.
TYPED_TEST(SequenceLocalStorageSlotTest, GetWithoutSetDefaultConstructs) {
struct DefaultConstructable {
int x = 0x12345678;
};
using SLSType = typename TypeParam::template Type<DefaultConstructable>;
SLSType slot;
EXPECT_EQ(slot.GetOrCreateValue().x, 0x12345678);
}
// Verify that a GetOrCreateValue() without a previous emplace() 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.
TYPED_TEST(SequenceLocalStorageSlotTest, GetWithoutSetDefaultConstructsPOD) {
using SLSType = typename TypeParam::template Type<void*>;
SLSType slot;
EXPECT_EQ(slot.GetOrCreateValue(), nullptr);
}
// Verify that the value of a slot is specific to a SequenceLocalStorageMap
TEST(SequenceLocalStorageSlotMultipleMapTest, EmplaceGetMultipleMapsOneSlot) {
SequenceLocalStorageSlot<unsigned int> slot;
std::array<internal::SequenceLocalStorageMap, 5> sequence_local_storage_maps;
// Set the value of the slot to be the index of the current
// SequenceLocalStorageMaps in the vector
for (unsigned int i = 0; i < std::size(sequence_local_storage_maps); ++i) {
internal::ScopedSetSequenceLocalStorageMapForCurrentThread
scoped_sequence_local_storage(&sequence_local_storage_maps[i]);
slot.emplace(i);
}
for (unsigned int i = 0; i < std::size(sequence_local_storage_maps); ++i) {
internal::ScopedSetSequenceLocalStorageMapForCurrentThread
scoped_sequence_local_storage(&sequence_local_storage_maps[i]);
EXPECT_EQ(*slot, i);
}
}
TEST(SequenceLocalStorageComPtrTest,
TestClassesWithNoAddressOfOperatorCanCompile) {
internal::SequenceLocalStorageMap sequence_local_storage_map;
internal::ScopedSetSequenceLocalStorageMapForCurrentThread
scoped_sequence_local_storage(&sequence_local_storage_map);
// Microsoft::WRL::ComPtr overrides & operator to release the underlying
// pointer.
// https://learn.microsoft.com/en-us/cpp/cppcx/wrl/comptr-class?view=msvc-170#operator-ampersand
// Types stored in SequenceLocalStorage may override `operator&` to have
// additional side effects, e.g. Microsoft::WRL::ComPtr. Make sure
// SequenceLocalStorage does not invoke/use custom `operator&`s to avoid
// triggering those side effects.
class TestNoAddressOfOperator {
public:
TestNoAddressOfOperator() = default;
// Define a non-trivial destructor so that SequenceLocalStorageSlot will use
// the external value path.
~TestNoAddressOfOperator() {} // NOLINT(modernize-use-equals-default)
// See note above class definition for the reason this operator is deleted.
TestNoAddressOfOperator* operator&() = delete;
};
SequenceLocalStorageSlot<TestNoAddressOfOperator> slot;
slot.emplace(TestNoAddressOfOperator());
EXPECT_NE(slot.GetValuePointer(), nullptr);
}
} // namespace base
|