/* * Copyright 2016 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "rtc_base/weak_ptr.h" #include #include #include "rtc_base/event.h" #include "rtc_base/task_queue_for_test.h" #include "test/gtest.h" namespace rtc { namespace { struct Base { std::string member; }; struct Derived : public Base {}; struct Target {}; struct Arrow { WeakPtr target; }; struct TargetWithFactory : public Target { TargetWithFactory() : factory(this) {} WeakPtrFactory factory; }; } // namespace TEST(WeakPtrFactoryTest, Basic) { int data; WeakPtrFactory factory(&data); WeakPtr ptr = factory.GetWeakPtr(); EXPECT_EQ(&data, ptr.get()); } TEST(WeakPtrFactoryTest, Comparison) { int data; WeakPtrFactory factory(&data); WeakPtr ptr = factory.GetWeakPtr(); WeakPtr ptr2 = ptr; EXPECT_EQ(ptr.get(), ptr2.get()); } TEST(WeakPtrFactoryTest, Move) { int data; WeakPtrFactory factory(&data); WeakPtr ptr = factory.GetWeakPtr(); WeakPtr ptr2 = factory.GetWeakPtr(); WeakPtr ptr3 = std::move(ptr2); EXPECT_NE(ptr.get(), ptr2.get()); EXPECT_EQ(ptr.get(), ptr3.get()); } TEST(WeakPtrFactoryTest, OutOfScope) { WeakPtr ptr; EXPECT_EQ(nullptr, ptr.get()); { int data; WeakPtrFactory factory(&data); ptr = factory.GetWeakPtr(); EXPECT_EQ(&data, ptr.get()); } EXPECT_EQ(nullptr, ptr.get()); } TEST(WeakPtrFactoryTest, Multiple) { WeakPtr a, b; { int data; WeakPtrFactory factory(&data); a = factory.GetWeakPtr(); b = factory.GetWeakPtr(); EXPECT_EQ(&data, a.get()); EXPECT_EQ(&data, b.get()); } EXPECT_EQ(nullptr, a.get()); EXPECT_EQ(nullptr, b.get()); } TEST(WeakPtrFactoryTest, MultipleStaged) { WeakPtr a; { int data; WeakPtrFactory factory(&data); a = factory.GetWeakPtr(); { WeakPtr b = factory.GetWeakPtr(); } EXPECT_NE(nullptr, a.get()); } EXPECT_EQ(nullptr, a.get()); } TEST(WeakPtrFactoryTest, Dereference) { Base data; data.member = "123456"; WeakPtrFactory factory(&data); WeakPtr ptr = factory.GetWeakPtr(); EXPECT_EQ(&data, ptr.get()); EXPECT_EQ(data.member, (*ptr).member); EXPECT_EQ(data.member, ptr->member); } TEST(WeakPtrFactoryTest, UpCast) { Derived data; WeakPtrFactory factory(&data); WeakPtr ptr = factory.GetWeakPtr(); ptr = factory.GetWeakPtr(); EXPECT_EQ(ptr.get(), &data); } TEST(WeakPtrTest, DefaultConstructor) { WeakPtr ptr; EXPECT_EQ(nullptr, ptr.get()); } TEST(WeakPtrFactoryTest, BooleanTesting) { int data; WeakPtrFactory factory(&data); WeakPtr ptr_to_an_instance = factory.GetWeakPtr(); EXPECT_TRUE(ptr_to_an_instance); EXPECT_FALSE(!ptr_to_an_instance); if (ptr_to_an_instance) { } else { ADD_FAILURE() << "Pointer to an instance should result in true."; } if (!ptr_to_an_instance) { // check for operator!(). ADD_FAILURE() << "Pointer to an instance should result in !x being false."; } WeakPtr null_ptr; EXPECT_FALSE(null_ptr); EXPECT_TRUE(!null_ptr); if (null_ptr) { ADD_FAILURE() << "Null pointer should result in false."; } if (!null_ptr) { // check for operator!(). } else { ADD_FAILURE() << "Null pointer should result in !x being true."; } } TEST(WeakPtrFactoryTest, ComparisonToNull) { int data; WeakPtrFactory factory(&data); WeakPtr ptr_to_an_instance = factory.GetWeakPtr(); EXPECT_NE(nullptr, ptr_to_an_instance); EXPECT_NE(ptr_to_an_instance, nullptr); WeakPtr null_ptr; EXPECT_EQ(null_ptr, nullptr); EXPECT_EQ(nullptr, null_ptr); } TEST(WeakPtrTest, InvalidateWeakPtrs) { int data; WeakPtrFactory factory(&data); WeakPtr ptr = factory.GetWeakPtr(); EXPECT_EQ(&data, ptr.get()); EXPECT_TRUE(factory.HasWeakPtrs()); factory.InvalidateWeakPtrs(); EXPECT_EQ(nullptr, ptr.get()); EXPECT_FALSE(factory.HasWeakPtrs()); // Test that the factory can create new weak pointers after a // InvalidateWeakPtrs call, and they remain valid until the next // InvalidateWeakPtrs call. WeakPtr ptr2 = factory.GetWeakPtr(); EXPECT_EQ(&data, ptr2.get()); EXPECT_TRUE(factory.HasWeakPtrs()); factory.InvalidateWeakPtrs(); EXPECT_EQ(nullptr, ptr2.get()); EXPECT_FALSE(factory.HasWeakPtrs()); } TEST(WeakPtrTest, HasWeakPtrs) { int data; WeakPtrFactory factory(&data); { WeakPtr ptr = factory.GetWeakPtr(); EXPECT_TRUE(factory.HasWeakPtrs()); } EXPECT_FALSE(factory.HasWeakPtrs()); } template std::unique_ptr NewObjectCreatedOnTaskQueue() { std::unique_ptr obj; webrtc::TaskQueueForTest queue("NewObjectCreatedOnTaskQueue"); queue.SendTask([&] { obj = std::make_unique(); }); return obj; } TEST(WeakPtrTest, ObjectAndWeakPtrOnDifferentThreads) { // Test that it is OK to create an object with a WeakPtrFactory one thread, // but use it on another. This tests that we do not trip runtime checks that // ensure that a WeakPtr is not used by multiple threads. std::unique_ptr target( NewObjectCreatedOnTaskQueue()); WeakPtr weak_ptr = target->factory.GetWeakPtr(); EXPECT_EQ(target.get(), weak_ptr.get()); } TEST(WeakPtrTest, WeakPtrInitiateAndUseOnDifferentThreads) { // Test that it is OK to create a WeakPtr on one thread, but use it on // another. This tests that we do not trip runtime checks that ensure that a // WeakPtr is not used by multiple threads. auto target = std::make_unique(); // Create weak ptr on main thread WeakPtr weak_ptr = target->factory.GetWeakPtr(); webrtc::TaskQueueForTest queue("queue"); queue.SendTask([&] { // Dereference and invalide weak_ptr on another thread. EXPECT_EQ(weak_ptr.get(), target.get()); target.reset(); }); } } // namespace rtc