| // 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()); |
| } |