blob: aafcf16b3d7083dd593c307a98eff226363e352d [file] [log] [blame]
// Copyright 2016 PDFium 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 "core/fxcrt/cfx_weak_ptr.h"
#include <memory>
#include <utility>
#include "core/fxcrt/fx_memory.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
class PseudoDeletable;
using WeakPtr = CFX_WeakPtr<PseudoDeletable, ReleaseDeleter<PseudoDeletable>>;
using UniquePtr =
std::unique_ptr<PseudoDeletable, ReleaseDeleter<PseudoDeletable>>;
class PseudoDeletable {
public:
PseudoDeletable() : delete_count_(0) {}
void Release() {
++delete_count_;
next_.Reset();
}
void SetNext(const WeakPtr& next) { next_ = next; }
int delete_count() const { return delete_count_; }
private:
int delete_count_;
WeakPtr next_;
};
} // namespace
TEST(fxcrt, WeakPtrNull) {
WeakPtr ptr1;
EXPECT_FALSE(ptr1);
WeakPtr ptr2;
EXPECT_TRUE(ptr1 == ptr2);
EXPECT_FALSE(ptr1 != ptr2);
WeakPtr ptr3(ptr1);
EXPECT_TRUE(ptr1 == ptr3);
EXPECT_FALSE(ptr1 != ptr3);
WeakPtr ptr4 = ptr1;
EXPECT_TRUE(ptr1 == ptr4);
EXPECT_FALSE(ptr1 != ptr4);
}
TEST(fxcrt, WeakPtrNonNull) {
PseudoDeletable thing;
EXPECT_EQ(0, thing.delete_count());
{
UniquePtr unique(&thing);
WeakPtr ptr1(std::move(unique));
EXPECT_TRUE(ptr1);
EXPECT_EQ(&thing, ptr1.Get());
WeakPtr ptr2;
EXPECT_FALSE(ptr1 == ptr2);
EXPECT_TRUE(ptr1 != ptr2);
{
WeakPtr ptr3(ptr1);
EXPECT_TRUE(ptr1 == ptr3);
EXPECT_FALSE(ptr1 != ptr3);
EXPECT_EQ(&thing, ptr3.Get());
{
WeakPtr ptr4 = ptr1;
EXPECT_TRUE(ptr1 == ptr4);
EXPECT_FALSE(ptr1 != ptr4);
EXPECT_EQ(&thing, ptr4.Get());
}
}
EXPECT_EQ(0, thing.delete_count());
}
EXPECT_EQ(1, thing.delete_count());
}
TEST(fxcrt, WeakPtrResetNull) {
PseudoDeletable thing;
{
UniquePtr unique(&thing);
WeakPtr ptr1(std::move(unique));
WeakPtr ptr2 = ptr1;
ptr1.Reset();
EXPECT_FALSE(ptr1);
EXPECT_EQ(nullptr, ptr1.Get());
EXPECT_TRUE(ptr2);
EXPECT_EQ(&thing, ptr2.Get());
EXPECT_FALSE(ptr1 == ptr2);
EXPECT_TRUE(ptr1 != ptr2);
EXPECT_EQ(0, thing.delete_count());
}
EXPECT_EQ(1, thing.delete_count());
}
TEST(fxcrt, WeakPtrResetNonNull) {
PseudoDeletable thing1;
PseudoDeletable thing2;
{
UniquePtr unique1(&thing1);
WeakPtr ptr1(std::move(unique1));
WeakPtr ptr2 = ptr1;
UniquePtr unique2(&thing2);
ptr2.Reset(std::move(unique2));
EXPECT_TRUE(ptr1);
EXPECT_EQ(&thing1, ptr1.Get());
EXPECT_TRUE(ptr2);
EXPECT_EQ(&thing2, ptr2.Get());
EXPECT_FALSE(ptr1 == ptr2);
EXPECT_TRUE(ptr1 != ptr2);
EXPECT_EQ(0, thing1.delete_count());
EXPECT_EQ(0, thing2.delete_count());
}
EXPECT_EQ(1, thing1.delete_count());
EXPECT_EQ(1, thing2.delete_count());
}
TEST(fxcrt, WeakPtrDeleteObject) {
PseudoDeletable thing;
{
UniquePtr unique(&thing);
WeakPtr ptr1(std::move(unique));
WeakPtr ptr2 = ptr1;
ptr1.DeleteObject();
EXPECT_FALSE(ptr1);
EXPECT_EQ(nullptr, ptr1.Get());
EXPECT_FALSE(ptr2);
EXPECT_EQ(nullptr, ptr2.Get());
EXPECT_FALSE(ptr1 == ptr2);
EXPECT_TRUE(ptr1 != ptr2);
EXPECT_EQ(1, thing.delete_count());
}
EXPECT_EQ(1, thing.delete_count());
}
TEST(fxcrt, WeakPtrCyclic) {
PseudoDeletable thing1;
PseudoDeletable thing2;
{
UniquePtr unique1(&thing1);
UniquePtr unique2(&thing2);
WeakPtr ptr1(std::move(unique1));
WeakPtr ptr2(std::move(unique2));
ptr1->SetNext(ptr2);
ptr2->SetNext(ptr1);
}
// Leaks without explicit clear.
EXPECT_EQ(0, thing1.delete_count());
EXPECT_EQ(0, thing2.delete_count());
}
TEST(fxcrt, WeakPtrCyclicDeleteObject) {
PseudoDeletable thing1;
PseudoDeletable thing2;
{
UniquePtr unique1(&thing1);
UniquePtr unique2(&thing2);
WeakPtr ptr1(std::move(unique1));
WeakPtr ptr2(std::move(unique2));
ptr1->SetNext(ptr2);
ptr2->SetNext(ptr1);
ptr1.DeleteObject();
EXPECT_EQ(1, thing1.delete_count());
EXPECT_EQ(0, thing2.delete_count());
}
EXPECT_EQ(1, thing1.delete_count());
EXPECT_EQ(1, thing2.delete_count());
}