TestSafeRefPtr.cpp (6948B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "gtest/gtest.h" 8 #include "mozilla/RefCounted.h" 9 #include "mozilla/dom/SafeRefPtr.h" 10 11 using namespace mozilla; 12 13 class SafeBase : public SafeRefCounted<SafeBase> { 14 public: 15 MOZ_DECLARE_REFCOUNTED_TYPENAME(SafeBase) 16 17 SafeBase() : mDead(false) {} 18 19 static inline int sNumDestroyed; 20 21 ~SafeBase() { 22 MOZ_RELEASE_ASSERT(!mDead); 23 mDead = true; 24 sNumDestroyed++; 25 } 26 27 private: 28 bool mDead; 29 }; 30 struct SafeDerived : public SafeBase {}; 31 32 class Base : public RefCounted<Base> { 33 public: 34 MOZ_DECLARE_REFCOUNTED_TYPENAME(Base) 35 36 Base() : mDead(false) {} 37 38 static inline int sNumDestroyed; 39 40 ~Base() { 41 MOZ_RELEASE_ASSERT(!mDead); 42 mDead = true; 43 sNumDestroyed++; 44 } 45 46 private: 47 bool mDead; 48 }; 49 50 struct Derived : public Base {}; 51 52 already_AddRefed<Base> NewFoo() { 53 RefPtr<Base> ptr(new Base()); 54 return ptr.forget(); 55 } 56 57 already_AddRefed<Base> NewBar() { 58 RefPtr<Derived> bar = new Derived(); 59 return bar.forget(); 60 } 61 62 TEST(DOM_IndexedDB_SafeRefPtr, Construct_Default) 63 { 64 Base::sNumDestroyed = 0; 65 { 66 SafeRefPtr<Base> ptr; 67 ASSERT_FALSE(ptr); 68 ASSERT_EQ(0, Base::sNumDestroyed); 69 } 70 ASSERT_EQ(0, Base::sNumDestroyed); 71 } 72 73 TEST(DOM_IndexedDB_SafeRefPtr, Construct_FromNullPtr) 74 { 75 Base::sNumDestroyed = 0; 76 { 77 SafeRefPtr<Base> ptr = nullptr; 78 ASSERT_FALSE(ptr); 79 ASSERT_EQ(0, Base::sNumDestroyed); 80 } 81 ASSERT_EQ(0, Base::sNumDestroyed); 82 } 83 84 TEST(DOM_IndexedDB_SafeRefPtr, Construct_FromMakeSafeRefPtr_SafeRefCounted) 85 { 86 SafeBase::sNumDestroyed = 0; 87 { 88 SafeRefPtr<SafeBase> ptr = MakeSafeRefPtr<SafeBase>(); 89 ASSERT_TRUE(ptr); 90 ASSERT_EQ(1u, ptr->refCount()); 91 } 92 ASSERT_EQ(1, SafeBase::sNumDestroyed); 93 } 94 95 TEST(DOM_IndexedDB_SafeRefPtr, 96 Construct_FromMakeSafeRefPtr_SafeRefCounted_DerivedType) 97 { 98 SafeBase::sNumDestroyed = 0; 99 { 100 SafeRefPtr<SafeBase> ptr = MakeSafeRefPtr<SafeDerived>(); 101 ASSERT_TRUE(ptr); 102 ASSERT_EQ(1u, ptr->refCount()); 103 } 104 ASSERT_EQ(1, SafeBase::sNumDestroyed); 105 } 106 107 TEST(DOM_IndexedDB_SafeRefPtr, Construct_FromMakeSafeRefPtr_RefCounted) 108 { 109 Base::sNumDestroyed = 0; 110 { 111 SafeRefPtr<Base> ptr = MakeSafeRefPtr<Base>(); 112 ASSERT_TRUE(ptr); 113 ASSERT_EQ(1u, ptr->refCount()); 114 } 115 ASSERT_EQ(1, Base::sNumDestroyed); 116 } 117 118 TEST(DOM_IndexedDB_SafeRefPtr, Construct_FromRefPtr) 119 { 120 Base::sNumDestroyed = 0; 121 { 122 SafeRefPtr<Base> ptr = SafeRefPtr{MakeRefPtr<Base>()}; 123 ASSERT_TRUE(ptr); 124 ASSERT_EQ(1u, ptr->refCount()); 125 } 126 ASSERT_EQ(1, Base::sNumDestroyed); 127 } 128 129 TEST(DOM_IndexedDB_SafeRefPtr, Construct_FromRefPtr_DerivedType) 130 { 131 Base::sNumDestroyed = 0; 132 { 133 SafeRefPtr<Base> ptr = SafeRefPtr{MakeRefPtr<Derived>()}; 134 ASSERT_TRUE(ptr); 135 ASSERT_EQ(1u, ptr->refCount()); 136 } 137 ASSERT_EQ(1, Base::sNumDestroyed); 138 } 139 140 TEST(DOM_IndexedDB_SafeRefPtr, Construct_FromAlreadyAddRefed) 141 { 142 Base::sNumDestroyed = 0; 143 { 144 SafeRefPtr<Base> ptr1 = SafeRefPtr{NewFoo()}; 145 SafeRefPtr<Base> ptr2(NewFoo()); 146 ASSERT_TRUE(ptr1); 147 ASSERT_TRUE(ptr2); 148 ASSERT_EQ(0, Base::sNumDestroyed); 149 } 150 ASSERT_EQ(2, Base::sNumDestroyed); 151 } 152 153 TEST(DOM_IndexedDB_SafeRefPtr, Construct_FromAlreadyAddRefed_DerivedType) 154 { 155 Base::sNumDestroyed = 0; 156 { 157 SafeRefPtr<Base> ptr = SafeRefPtr{NewBar()}; 158 ASSERT_TRUE(ptr); 159 ASSERT_EQ(1u, ptr->refCount()); 160 ASSERT_EQ(0, Base::sNumDestroyed); 161 } 162 ASSERT_EQ(1, Base::sNumDestroyed); 163 } 164 165 TEST(DOM_IndexedDB_SafeRefPtr, Construct_FromRawPtr) 166 { 167 Base::sNumDestroyed = 0; 168 { 169 SafeRefPtr<Base> ptr = SafeRefPtr{new Base(), AcquireStrongRefFromRawPtr{}}; 170 ASSERT_TRUE(ptr); 171 ASSERT_EQ(1u, ptr->refCount()); 172 ASSERT_EQ(0, Base::sNumDestroyed); 173 } 174 ASSERT_EQ(1, Base::sNumDestroyed); 175 } 176 177 TEST(DOM_IndexedDB_SafeRefPtr, Construct_FromRawPtr_Dervied) 178 { 179 Base::sNumDestroyed = 0; 180 { 181 SafeRefPtr<Base> ptr = 182 SafeRefPtr{new Derived(), AcquireStrongRefFromRawPtr{}}; 183 ASSERT_TRUE(ptr); 184 ASSERT_EQ(1u, ptr->refCount()); 185 ASSERT_EQ(0, Base::sNumDestroyed); 186 } 187 ASSERT_EQ(1, Base::sNumDestroyed); 188 } 189 190 TEST(DOM_IndexedDB_SafeRefPtr, ClonePtr) 191 { 192 Base::sNumDestroyed = 0; 193 { 194 SafeRefPtr<Base> ptr1; 195 { 196 ptr1 = MakeSafeRefPtr<Base>(); 197 const SafeRefPtr<Base> ptr2 = ptr1.clonePtr(); 198 SafeRefPtr<Base> f3 = ptr2.clonePtr(); 199 200 ASSERT_EQ(3u, ptr1->refCount()); 201 ASSERT_EQ(0, Base::sNumDestroyed); 202 } 203 ASSERT_EQ(1u, ptr1->refCount()); 204 ASSERT_EQ(0, Base::sNumDestroyed); 205 } 206 ASSERT_EQ(1, Base::sNumDestroyed); 207 } 208 209 TEST(DOM_IndexedDB_SafeRefPtr, Forget) 210 { 211 Base::sNumDestroyed = 0; 212 { 213 SafeRefPtr<Base> ptr1 = MakeSafeRefPtr<Base>(); 214 SafeRefPtr<Base> ptr2 = SafeRefPtr{ptr1.forget()}; 215 216 ASSERT_FALSE(ptr1); 217 ASSERT_TRUE(ptr2); 218 ASSERT_EQ(1u, ptr2->refCount()); 219 } 220 ASSERT_EQ(1, Base::sNumDestroyed); 221 } 222 223 TEST(DOM_IndexedDB_SafeRefPtr, Downcast) 224 { 225 Base::sNumDestroyed = 0; 226 { 227 SafeRefPtr<Base> ptr1 = MakeSafeRefPtr<Derived>(); 228 SafeRefPtr<Derived> ptr2 = std::move(ptr1).downcast<Derived>(); 229 230 ASSERT_FALSE(ptr1); 231 ASSERT_TRUE(ptr2); 232 ASSERT_EQ(1u, ptr2->refCount()); 233 } 234 ASSERT_EQ(1, Base::sNumDestroyed); 235 } 236 237 struct SafeTest final : SafeBase { 238 template <typename Func> 239 explicit SafeTest(Func aCallback) { 240 aCallback(SafeRefPtrFromThis()); 241 } 242 }; 243 244 TEST(DOM_IndexedDB_SafeRefPtr, SafeRefPtrFromThis_StoreFromCtor) 245 { 246 SafeBase::sNumDestroyed = 0; 247 { 248 SafeRefPtr<SafeBase> ptr1; 249 { 250 SafeRefPtr<SafeTest> ptr2 = 251 MakeSafeRefPtr<SafeTest>([&ptr1](SafeRefPtr<SafeBase> ptr) { 252 ptr1 = std::move(ptr); 253 EXPECT_EQ(2u, ptr1->refCount()); 254 }); 255 ASSERT_EQ(2u, ptr2->refCount()); 256 } 257 ASSERT_EQ(0, SafeBase::sNumDestroyed); 258 ASSERT_EQ(1u, ptr1->refCount()); 259 } 260 ASSERT_EQ(1, SafeBase::sNumDestroyed); 261 } 262 263 TEST(DOM_IndexedDB_SafeRefPtr, SafeRefPtrFromThis_DiscardInCtor) 264 { 265 SafeBase::sNumDestroyed = 0; 266 { 267 SafeRefPtr<SafeTest> ptr = MakeSafeRefPtr<SafeTest>( 268 [](SafeRefPtr<SafeBase> ptr) { EXPECT_EQ(2u, ptr->refCount()); }); 269 ASSERT_EQ(1u, ptr->refCount()); 270 ASSERT_EQ(0, SafeBase::sNumDestroyed); 271 } 272 ASSERT_EQ(1, SafeBase::sNumDestroyed); 273 } 274 275 TEST(DOM_IndexedDB_SafeRefPtr, Construct_FromSelf) 276 { 277 SafeBase::sNumDestroyed = 0; 278 { 279 SafeRefPtr<SafeBase> ptr = MakeSafeRefPtr<SafeBase>(); 280 ptr = std::move(static_cast<SafeRefPtr<SafeBase>&>(ptr)); 281 ASSERT_EQ(1u, ptr->refCount()); 282 ASSERT_EQ(0, SafeBase::sNumDestroyed); 283 } 284 ASSERT_EQ(1, SafeBase::sNumDestroyed); 285 } 286 287 static_assert( 288 std::is_same_v<SafeRefPtr<Base>, 289 decltype(std::declval<bool>() ? MakeSafeRefPtr<Derived>() 290 : MakeSafeRefPtr<Base>())>);