| // Copyright 2024 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 "quiche/common/quiche_weak_ptr.h" | |
| #include <utility> | |
| #include "absl/container/flat_hash_set.h" | |
| #include "absl/hash/hash.h" | |
| #include "quiche/common/platform/api/quiche_test.h" | |
| namespace quiche { | |
| namespace { | |
| class TestClass { | |
| public: | |
| QuicheWeakPtr<TestClass> CreateWeakPtr() { return weak_factory_.Create(); } | |
| private: | |
| QuicheWeakPtrFactory<TestClass> weak_factory_{this}; | |
| }; | |
| TEST(QuicheWeakPtrTest, Empty) { | |
| QuicheWeakPtr<TestClass> ptr; | |
| EXPECT_FALSE(ptr.IsValid()); | |
| EXPECT_EQ(ptr.GetIfAvailable(), nullptr); | |
| } | |
| TEST(QuicheWeakPtrTest, Valid) { | |
| TestClass object; | |
| QuicheWeakPtr<TestClass> ptr = object.CreateWeakPtr(); | |
| EXPECT_TRUE(ptr.IsValid()); | |
| EXPECT_EQ(ptr.GetIfAvailable(), &object); | |
| } | |
| TEST(QuicheWeakPtrTest, ValidCopy) { | |
| TestClass object; | |
| QuicheWeakPtr<TestClass> ptr = object.CreateWeakPtr(); | |
| QuicheWeakPtr<TestClass> ptr_copy = ptr; | |
| EXPECT_TRUE(ptr.IsValid()); | |
| EXPECT_TRUE(ptr_copy.IsValid()); | |
| EXPECT_EQ(ptr.GetIfAvailable(), &object); | |
| EXPECT_EQ(ptr_copy.GetIfAvailable(), &object); | |
| } | |
| TEST(QuicheWeakPtrTest, EmptyAfterMove) { | |
| TestClass object; | |
| QuicheWeakPtr<TestClass> ptr = object.CreateWeakPtr(); | |
| QuicheWeakPtr<TestClass> ptr_moved = std::move(ptr); | |
| EXPECT_FALSE(ptr.IsValid()); // NOLINT(bugprone-use-after-move) | |
| EXPECT_TRUE(ptr_moved.IsValid()); | |
| EXPECT_EQ(ptr.GetIfAvailable(), nullptr); // NOLINT(bugprone-use-after-move) | |
| EXPECT_EQ(ptr_moved.GetIfAvailable(), &object); | |
| } | |
| TEST(QuicheWeakPtrTest, Expired) { | |
| QuicheWeakPtr<TestClass> ptr; | |
| { | |
| TestClass object; | |
| ptr = object.CreateWeakPtr(); | |
| EXPECT_TRUE(ptr.IsValid()); | |
| } | |
| EXPECT_FALSE(ptr.IsValid()); | |
| } | |
| TEST(QuicheWeakPtrTest, Eq) { | |
| alignas(TestClass) char data[sizeof(TestClass)]; | |
| // Two weak pointers to the same object are equal. | |
| TestClass* object1 = new (data) TestClass; | |
| QuicheWeakPtr<TestClass> ptr1 = object1->CreateWeakPtr(); | |
| QuicheWeakPtr<TestClass> ptr2 = object1->CreateWeakPtr(); | |
| EXPECT_EQ(ptr1, ptr2); | |
| // The equality continues to hold even if the original object got deleted. | |
| object1->~TestClass(); | |
| EXPECT_FALSE(ptr1.IsValid()); | |
| EXPECT_FALSE(ptr2.IsValid()); | |
| EXPECT_EQ(ptr1, ptr2); | |
| // If a new object gets allocated in the exact same spot, the weak pointer to | |
| // the old object is not equal to the weak pointer to the new object. | |
| TestClass* object2 = new (data) TestClass; | |
| QuicheWeakPtr<TestClass> ptr3 = object2->CreateWeakPtr(); | |
| EXPECT_NE(ptr1, ptr3); | |
| EXPECT_NE(ptr2, ptr3); | |
| EXPECT_EQ(ptr3.GetIfAvailable(), object1); | |
| // The null pointers are equal to themselves, but not to any object that is, | |
| // or was valid. | |
| QuicheWeakPtr<TestClass> ptr4; | |
| QuicheWeakPtr<TestClass> ptr5; | |
| EXPECT_EQ(ptr4, ptr5); | |
| EXPECT_NE(ptr4, ptr1); | |
| EXPECT_NE(ptr4, ptr3); | |
| object2->~TestClass(); | |
| } | |
| TEST(QuicheWeakPtrTest, Hash) { | |
| TestClass object; | |
| QuicheWeakPtr<TestClass> ptr1 = object.CreateWeakPtr(); | |
| QuicheWeakPtr<TestClass> ptr2 = object.CreateWeakPtr(); | |
| EXPECT_EQ(absl::HashOf(ptr1), absl::HashOf(ptr2)); | |
| absl::flat_hash_set<QuicheWeakPtr<TestClass>> set; | |
| EXPECT_EQ(set.size(), 0u); | |
| set.insert(ptr1); | |
| EXPECT_EQ(set.size(), 1u); | |
| set.insert(ptr2); | |
| EXPECT_EQ(set.size(), 1u); | |
| set.insert(TestClass().CreateWeakPtr()); | |
| EXPECT_EQ(set.size(), 2u); | |
| } | |
| } // namespace | |
| } // namespace quiche |