#include "base/memory/weak_auto_reset.h"
#include <memory>
#include "base/memory/weak_ptr.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
namespace {
template <class T>
class HasWeakFactory {
public:
HasWeakFactory() = default;
~HasWeakFactory() = default;
auto SetValueScoped(T value) {
return WeakAutoReset(factory_.GetWeakPtr(), &HasWeakFactory::value_,
std::move(value));
}
void set_value(T value) { value_ = std::move(value); }
const T& value() const { return value_; }
WeakPtr<HasWeakFactory> GetWeakPtr() { return factory_.GetWeakPtr(); }
private:
T value_ = T();
WeakPtrFactory<HasWeakFactory> factory_{this};
};
}
TEST(WeakAutoResetTest, DefaultConstructor) {
WeakAutoReset<HasWeakFactory<int>, int> empty;
}
TEST(WeakAutoResetTest, SingleAutoReset) {
HasWeakFactory<int> hwf;
{
WeakAutoReset reset = hwf.SetValueScoped(1);
EXPECT_EQ(1, hwf.value());
}
EXPECT_EQ(0, hwf.value());
}
TEST(WeakAutoResetTest, SingleAutoResetObjectDestroyed) {
auto hwf = std::make_unique<HasWeakFactory<int>>();
WeakAutoReset reset = hwf->SetValueScoped(1);
EXPECT_EQ(1, hwf->value());
hwf.reset();
}
TEST(WeakAutoResetTest, MultipleNested) {
HasWeakFactory<int> hwf;
{
WeakAutoReset reset = hwf.SetValueScoped(1);
EXPECT_EQ(1, hwf.value());
{
WeakAutoReset reset2 = hwf.SetValueScoped(2);
EXPECT_EQ(2, hwf.value());
}
EXPECT_EQ(1, hwf.value());
}
EXPECT_EQ(0, hwf.value());
}
TEST(WeakAutoResetTest, MultipleNestedObjectDestroyed) {
auto hwf = std::make_unique<HasWeakFactory<int>>();
WeakAutoReset reset = hwf->SetValueScoped(1);
EXPECT_EQ(1, hwf->value());
WeakAutoReset reset2 = hwf->SetValueScoped(2);
EXPECT_EQ(2, hwf->value());
hwf.reset();
}
TEST(WeakAutoResetTest, MoveAssignmentTransfersOwnership) {
HasWeakFactory<int> hwf;
WeakAutoReset reset = hwf.SetValueScoped(1);
{
WeakAutoReset<HasWeakFactory<int>, int> reset2;
EXPECT_EQ(1, hwf.value());
reset2 = std::move(reset);
EXPECT_EQ(1, hwf.value());
}
EXPECT_EQ(0, hwf.value());
}
TEST(WeakAutoResetTest, MoveAssignmentResetsOldValue) {
HasWeakFactory<int> hwf1;
HasWeakFactory<int> hwf2;
WeakAutoReset reset = hwf1.SetValueScoped(1);
WeakAutoReset reset2 = hwf2.SetValueScoped(2);
EXPECT_EQ(1, hwf1.value());
EXPECT_EQ(2, hwf2.value());
reset = std::move(reset2);
EXPECT_EQ(0, hwf1.value());
EXPECT_EQ(2, hwf2.value());
reset2 = WeakAutoReset<HasWeakFactory<int>, int>();
reset = WeakAutoReset<HasWeakFactory<int>, int>();
EXPECT_EQ(0, hwf1.value());
EXPECT_EQ(0, hwf2.value());
}
TEST(WeakAutoResetTest, MoveAssignmentToSelfIsNoOp) {
HasWeakFactory<int> hwf;
{
WeakAutoReset reset = hwf.SetValueScoped(1);
EXPECT_EQ(1, hwf.value());
auto* const reset_ref = &reset;
reset = std::move(*reset_ref);
EXPECT_EQ(1, hwf.value());
}
EXPECT_EQ(0, hwf.value());
}
TEST(WeakAutoResetTest, DeleteTargetObjectAfterMoveIsSafe) {
auto hwf = std::make_unique<HasWeakFactory<int>>();
WeakAutoReset reset = hwf->SetValueScoped(1);
WeakAutoReset reset2 = std::move(reset);
hwf.reset();
}
using HasWeakFactoryPointer = std::unique_ptr<HasWeakFactory<int>>;
TEST(WeakAutoResetTest, TestSafelyMovesValue) {
auto inner = std::make_unique<HasWeakFactory<int>>();
auto weak_ptr = inner->GetWeakPtr();
auto outer = std::make_unique<HasWeakFactory<HasWeakFactoryPointer>>();
outer->set_value(std::move(inner));
ASSERT_TRUE(weak_ptr);
{
WeakAutoReset reset = outer->SetValueScoped(HasWeakFactoryPointer());
EXPECT_TRUE(weak_ptr);
EXPECT_FALSE(outer->value());
}
EXPECT_TRUE(weak_ptr);
EXPECT_TRUE(outer->value());
outer.reset();
EXPECT_FALSE(weak_ptr);
}
TEST(WeakAutoResetTest, TestSafelyMovesValueAndThenDestroysIt) {
auto inner = std::make_unique<HasWeakFactory<int>>();
auto weak_ptr = inner->GetWeakPtr();
auto outer = std::make_unique<HasWeakFactory<HasWeakFactoryPointer>>();
outer->set_value(std::move(inner));
ASSERT_TRUE(weak_ptr);
{
WeakAutoReset reset = outer->SetValueScoped(HasWeakFactoryPointer());
EXPECT_TRUE(weak_ptr);
EXPECT_FALSE(outer->value());
outer.reset();
EXPECT_TRUE(weak_ptr);
}
EXPECT_FALSE(weak_ptr);
}
TEST(WeakAutoResetTest, TestMoveConstructorMovesOldValue) {
auto inner = std::make_unique<HasWeakFactory<int>>();
auto weak_ptr = inner->GetWeakPtr();
auto outer = std::make_unique<HasWeakFactory<HasWeakFactoryPointer>>();
outer->set_value(std::move(inner));
ASSERT_TRUE(weak_ptr);
{
WeakAutoReset reset = outer->SetValueScoped(HasWeakFactoryPointer());
EXPECT_TRUE(weak_ptr);
EXPECT_FALSE(outer->value());
{
WeakAutoReset reset2(std::move(reset));
EXPECT_TRUE(weak_ptr);
EXPECT_FALSE(outer->value());
}
EXPECT_TRUE(weak_ptr);
EXPECT_TRUE(outer->value());
}
}
TEST(WeakAutoResetTest, TestMoveAssignmentMovesOldValue) {
auto inner = std::make_unique<HasWeakFactory<int>>();
auto weak_ptr = inner->GetWeakPtr();
auto outer = std::make_unique<HasWeakFactory<HasWeakFactoryPointer>>();
outer->set_value(std::move(inner));
ASSERT_TRUE(weak_ptr);
{
WeakAutoReset<HasWeakFactory<HasWeakFactoryPointer>, HasWeakFactoryPointer>
reset;
{
WeakAutoReset reset2 = outer->SetValueScoped(HasWeakFactoryPointer());
EXPECT_TRUE(weak_ptr);
EXPECT_FALSE(outer->value());
reset = std::move(reset2);
EXPECT_TRUE(weak_ptr);
EXPECT_FALSE(outer->value());
}
EXPECT_TRUE(weak_ptr);
EXPECT_FALSE(outer->value());
}
EXPECT_TRUE(weak_ptr);
EXPECT_TRUE(outer->value());
}
TEST(WeakAutoResetTest, TestOldAndNewValuesAreSwapped) {
auto inner = std::make_unique<HasWeakFactory<int>>();
auto weak_ptr = inner->GetWeakPtr();
auto outer = std::make_unique<HasWeakFactory<HasWeakFactoryPointer>>();
outer->set_value(std::move(inner));
ASSERT_TRUE(weak_ptr);
auto replacement = std::make_unique<HasWeakFactory<int>>();
auto weak_ptr2 = replacement->GetWeakPtr();
{
WeakAutoReset reset = outer->SetValueScoped(std::move(replacement));
EXPECT_TRUE(weak_ptr);
EXPECT_TRUE(weak_ptr2);
EXPECT_EQ(weak_ptr2.get(), outer->value().get());
}
EXPECT_TRUE(weak_ptr);
EXPECT_FALSE(weak_ptr2);
EXPECT_EQ(weak_ptr.get(), outer->value().get());
}
}