blob: 6b486617ce7931f2b2bbbf1257ac4d96a156a31c [file] [log] [blame]
// Copyright (c) 2021 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/memory/safe_ref.h"
#include <utility>
#include "base/memory/weak_ptr.h"
#include "base/test/gtest_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace base {
namespace {
struct BaseClass {};
struct WithWeak : BaseClass {
~WithWeak() { self = nullptr; }
int i = 1;
WithWeak* self{this};
base::WeakPtrFactory<WithWeak> factory{this};
};
TEST(SafeRefTest, FromWeakPtrFactory) {
WithWeak with;
SafeRef<WithWeak> safe(with.factory.GetSafeRef());
}
TEST(SafeRefTest, Operators) {
WithWeak with;
SafeRef<WithWeak> safe(with.factory.GetSafeRef());
// operator->.
EXPECT_EQ(safe->self->i, 1); // Will crash if not live.
// operator*.
EXPECT_EQ((*safe).self->i, 1); // Will crash if not live.
}
TEST(SafeRefTest, CanCopyAndMove) {
WithWeak with;
SafeRef<WithWeak> safe(with.factory.GetSafeRef());
EXPECT_EQ(safe->self->i, 1); // Will crash if not live.
SafeRef<WithWeak> safe2 = safe; // Copy.
EXPECT_EQ(safe2->self->i, 1); // Will crash if not live.
EXPECT_EQ(safe->self->i, 1); // Will crash if not live.
SafeRef<WithWeak> safe3 = std::move(safe); // Move.
EXPECT_EQ(safe3->self->i, 1); // Will crash if not live.
}
TEST(SafeRefTest, StillValidAfterMove) {
WithWeak with;
SafeRef<WithWeak> safe(with.factory.GetSafeRef());
SafeRef<WithWeak> safe2 = std::move(safe); // Move.
EXPECT_EQ(safe->self->i, 1); // Will crash if not live.
EXPECT_EQ(safe2->self->i, 1); // Will crash if not live.
}
TEST(SafeRefTest, AssignCopyAndMove) {
WithWeak with;
SafeRef<WithWeak> safe(with.factory.GetSafeRef());
WithWeak with2;
SafeRef<WithWeak> safe2(with2.factory.GetSafeRef());
EXPECT_NE(safe->self, &with2);
safe = safe2;
EXPECT_EQ(safe->self, &with2);
WithWeak with3;
SafeRef<WithWeak> safe3(with3.factory.GetSafeRef());
EXPECT_NE(safe->self, &with3);
safe = std::move(safe3);
EXPECT_EQ(safe->self, &with3);
}
TEST(SafeRefTest, AssignCopyAfterInvalidate) {
WithWeak with;
SafeRef<WithWeak> safe(with.factory.GetSafeRef());
SafeRef<WithWeak> safe2(with.factory.GetSafeRef());
{
WithWeak with2;
safe = SafeRef<WithWeak>(with2.factory.GetSafeRef());
}
// `safe` is now invalidated (oops), but we won't use it in that state!
safe = safe2;
// `safe` is valid again, we can use it.
EXPECT_EQ(safe->self, &with);
}
TEST(SafeRefTest, AssignMoveAfterInvalidate) {
WithWeak with;
SafeRef<WithWeak> safe(with.factory.GetSafeRef());
SafeRef<WithWeak> safe2(with.factory.GetSafeRef());
{
WithWeak with2;
safe = SafeRef<WithWeak>(with2.factory.GetSafeRef());
}
// `safe` is now invalidated (oops), but we won't use it in that state!
safe = std::move(safe2);
// `safe` is valid again, we can use it.
EXPECT_EQ(safe->self, &with);
}
TEST(SafeRefDeathTest, ArrowOperatorCrashIfBadPointer) {
absl::optional<WithWeak> with(absl::in_place);
SafeRef<WithWeak> safe(with->factory.GetSafeRef());
with.reset();
EXPECT_CHECK_DEATH(safe.operator->()); // Will crash since not live.
}
TEST(SafeRefDeathTest, StarOperatorCrashIfBadPointer) {
absl::optional<WithWeak> with(absl::in_place);
SafeRef<WithWeak> safe(with->factory.GetSafeRef());
with.reset();
EXPECT_CHECK_DEATH(safe.operator*()); // Will crash since not live.
}
TEST(SafeRefTest, ConversionToBaseClassFromCopyAssign) {
WithWeak with;
SafeRef<WithWeak> safe(with.factory.GetSafeRef());
SafeRef<BaseClass> base_safe = safe;
EXPECT_EQ(static_cast<WithWeak*>(&*base_safe)->self, &with);
}
TEST(SafeRefTest, ConversionToBaseClassFromMoveAssign) {
WithWeak with;
SafeRef<WithWeak> safe(with.factory.GetSafeRef());
SafeRef<BaseClass> base_safe = std::move(safe);
EXPECT_EQ(static_cast<WithWeak*>(&*base_safe)->self, &with);
}
TEST(SafeRefTest, CanDerefConst) {
WithWeak with;
const SafeRef<WithWeak> safe(with.factory.GetSafeRef());
EXPECT_EQ(safe->self->i, 1);
EXPECT_EQ((*safe).self->i, 1);
}
} // namespace
} // namespace base