#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_;
};
}
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);
TYPED_TEST(SequenceLocalStorageSlotTest, GetEmplace) {
using SLSType = typename TypeParam::template Type<int>;
SLSType slot;
slot.emplace(5);
EXPECT_EQ(*slot, 5);
}
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);
}
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);
}
TYPED_TEST(SequenceLocalStorageSlotTest, GetReferenceModifiable) {
using SLSType = typename TypeParam::template Type<bool>;
SLSType slot;
slot.emplace(false);
*slot = true;
EXPECT_TRUE(*slot);
}
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);
}
TYPED_TEST(SequenceLocalStorageSlotTest, GetWithoutSetDefaultConstructs) {
struct DefaultConstructable {
int x = 0x12345678;
};
using SLSType = typename TypeParam::template Type<DefaultConstructable>;
SLSType slot;
EXPECT_EQ(slot.GetOrCreateValue().x, 0x12345678);
}
TYPED_TEST(SequenceLocalStorageSlotTest, GetWithoutSetDefaultConstructsPOD) {
using SLSType = typename TypeParam::template Type<void*>;
SLSType slot;
EXPECT_EQ(slot.GetOrCreateValue(), nullptr);
}
TEST(SequenceLocalStorageSlotMultipleMapTest, EmplaceGetMultipleMapsOneSlot) {
SequenceLocalStorageSlot<unsigned int> slot;
std::array<internal::SequenceLocalStorageMap, 5> sequence_local_storage_maps;
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);
class TestNoAddressOfOperator {
public:
TestNoAddressOfOperator() = default;
~TestNoAddressOfOperator() {}
TestNoAddressOfOperator* operator&() = delete;
};
SequenceLocalStorageSlot<TestNoAddressOfOperator> slot;
slot.emplace(TestNoAddressOfOperator());
EXPECT_NE(slot.GetValuePointer(), nullptr);
}
}