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