blob: d0ee6c89dc1cdaed93f9828f4b80a3dbe819b95f [file] [log] [blame] [edit]
// 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