1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/memory/ref_counted.h"
6
7 #include "base/test/opaque_ref_counted.h"
8 #include "testing/gtest/include/gtest/gtest.h"
9
10 namespace {
11
12 class SelfAssign : public base::RefCounted<SelfAssign> {
13 protected:
~SelfAssign()14 virtual ~SelfAssign() {}
15
16 private:
17 friend class base::RefCounted<SelfAssign>;
18 };
19
20 class Derived : public SelfAssign {
21 protected:
~Derived()22 ~Derived() override {}
23
24 private:
25 friend class base::RefCounted<Derived>;
26 };
27
28 class CheckDerivedMemberAccess : public scoped_refptr<SelfAssign> {
29 public:
CheckDerivedMemberAccess()30 CheckDerivedMemberAccess() {
31 // This shouldn't compile if we don't have access to the member variable.
32 SelfAssign** pptr = &ptr_;
33 EXPECT_EQ(*pptr, ptr_);
34 }
35 };
36
37 class ScopedRefPtrToSelf : public base::RefCounted<ScopedRefPtrToSelf> {
38 public:
ScopedRefPtrToSelf()39 ScopedRefPtrToSelf() : self_ptr_(this) {}
40
was_destroyed()41 static bool was_destroyed() { return was_destroyed_; }
42
reset_was_destroyed()43 static void reset_was_destroyed() { was_destroyed_ = false; }
44
45 scoped_refptr<ScopedRefPtrToSelf> self_ptr_;
46
47 private:
48 friend class base::RefCounted<ScopedRefPtrToSelf>;
~ScopedRefPtrToSelf()49 ~ScopedRefPtrToSelf() { was_destroyed_ = true; }
50
51 static bool was_destroyed_;
52 };
53
54 bool ScopedRefPtrToSelf::was_destroyed_ = false;
55
56 class ScopedRefPtrCountBase : public base::RefCounted<ScopedRefPtrCountBase> {
57 public:
ScopedRefPtrCountBase()58 ScopedRefPtrCountBase() { ++constructor_count_; }
59
constructor_count()60 static int constructor_count() { return constructor_count_; }
61
destructor_count()62 static int destructor_count() { return destructor_count_; }
63
reset_count()64 static void reset_count() {
65 constructor_count_ = 0;
66 destructor_count_ = 0;
67 }
68
69 protected:
~ScopedRefPtrCountBase()70 virtual ~ScopedRefPtrCountBase() { ++destructor_count_; }
71
72 private:
73 friend class base::RefCounted<ScopedRefPtrCountBase>;
74
75 static int constructor_count_;
76 static int destructor_count_;
77 };
78
79 int ScopedRefPtrCountBase::constructor_count_ = 0;
80 int ScopedRefPtrCountBase::destructor_count_ = 0;
81
82 class ScopedRefPtrCountDerived : public ScopedRefPtrCountBase {
83 public:
ScopedRefPtrCountDerived()84 ScopedRefPtrCountDerived() { ++constructor_count_; }
85
constructor_count()86 static int constructor_count() { return constructor_count_; }
87
destructor_count()88 static int destructor_count() { return destructor_count_; }
89
reset_count()90 static void reset_count() {
91 constructor_count_ = 0;
92 destructor_count_ = 0;
93 }
94
95 protected:
~ScopedRefPtrCountDerived()96 ~ScopedRefPtrCountDerived() override { ++destructor_count_; }
97
98 private:
99 friend class base::RefCounted<ScopedRefPtrCountDerived>;
100
101 static int constructor_count_;
102 static int destructor_count_;
103 };
104
105 int ScopedRefPtrCountDerived::constructor_count_ = 0;
106 int ScopedRefPtrCountDerived::destructor_count_ = 0;
107
108 class Other : public base::RefCounted<Other> {
109 private:
110 friend class base::RefCounted<Other>;
111
~Other()112 ~Other() {}
113 };
114
Overloaded(scoped_refptr<Other> other)115 scoped_refptr<Other> Overloaded(scoped_refptr<Other> other) {
116 return other;
117 }
118
Overloaded(scoped_refptr<SelfAssign> self_assign)119 scoped_refptr<SelfAssign> Overloaded(scoped_refptr<SelfAssign> self_assign) {
120 return self_assign;
121 }
122
123
124 } // end namespace
125
TEST(RefCountedUnitTest,TestSelfAssignment)126 TEST(RefCountedUnitTest, TestSelfAssignment) {
127 SelfAssign* p = new SelfAssign;
128 scoped_refptr<SelfAssign> var(p);
129 var = var;
130 EXPECT_EQ(var.get(), p);
131 }
132
TEST(RefCountedUnitTest,ScopedRefPtrMemberAccess)133 TEST(RefCountedUnitTest, ScopedRefPtrMemberAccess) {
134 CheckDerivedMemberAccess check;
135 }
136
TEST(RefCountedUnitTest,ScopedRefPtrToSelfPointerAssignment)137 TEST(RefCountedUnitTest, ScopedRefPtrToSelfPointerAssignment) {
138 ScopedRefPtrToSelf::reset_was_destroyed();
139
140 ScopedRefPtrToSelf* check = new ScopedRefPtrToSelf();
141 EXPECT_FALSE(ScopedRefPtrToSelf::was_destroyed());
142 check->self_ptr_ = nullptr;
143 EXPECT_TRUE(ScopedRefPtrToSelf::was_destroyed());
144 }
145
TEST(RefCountedUnitTest,ScopedRefPtrToSelfMoveAssignment)146 TEST(RefCountedUnitTest, ScopedRefPtrToSelfMoveAssignment) {
147 ScopedRefPtrToSelf::reset_was_destroyed();
148
149 ScopedRefPtrToSelf* check = new ScopedRefPtrToSelf();
150 EXPECT_FALSE(ScopedRefPtrToSelf::was_destroyed());
151 // Releasing |check->self_ptr_| will delete |check|.
152 // The move assignment operator must assign |check->self_ptr_| first then
153 // release |check->self_ptr_|.
154 check->self_ptr_ = scoped_refptr<ScopedRefPtrToSelf>();
155 EXPECT_TRUE(ScopedRefPtrToSelf::was_destroyed());
156 }
157
TEST(RefCountedUnitTest,ScopedRefPtrToOpaque)158 TEST(RefCountedUnitTest, ScopedRefPtrToOpaque) {
159 scoped_refptr<base::OpaqueRefCounted> p = base::MakeOpaqueRefCounted();
160 base::TestOpaqueRefCounted(p);
161
162 scoped_refptr<base::OpaqueRefCounted> q;
163 q = p;
164 base::TestOpaqueRefCounted(p);
165 base::TestOpaqueRefCounted(q);
166 }
167
TEST(RefCountedUnitTest,BooleanTesting)168 TEST(RefCountedUnitTest, BooleanTesting) {
169 scoped_refptr<SelfAssign> ptr_to_an_instance = new SelfAssign;
170 EXPECT_TRUE(ptr_to_an_instance);
171 EXPECT_FALSE(!ptr_to_an_instance);
172
173 if (ptr_to_an_instance) {
174 } else {
175 ADD_FAILURE() << "Pointer to an instance should result in true.";
176 }
177
178 if (!ptr_to_an_instance) { // check for operator!().
179 ADD_FAILURE() << "Pointer to an instance should result in !x being false.";
180 }
181
182 scoped_refptr<SelfAssign> null_ptr;
183 EXPECT_FALSE(null_ptr);
184 EXPECT_TRUE(!null_ptr);
185
186 if (null_ptr) {
187 ADD_FAILURE() << "Null pointer should result in false.";
188 }
189
190 if (!null_ptr) { // check for operator!().
191 } else {
192 ADD_FAILURE() << "Null pointer should result in !x being true.";
193 }
194 }
195
TEST(RefCountedUnitTest,Equality)196 TEST(RefCountedUnitTest, Equality) {
197 scoped_refptr<SelfAssign> p1(new SelfAssign);
198 scoped_refptr<SelfAssign> p2(new SelfAssign);
199
200 EXPECT_EQ(p1, p1);
201 EXPECT_EQ(p2, p2);
202
203 EXPECT_NE(p1, p2);
204 EXPECT_NE(p2, p1);
205 }
206
TEST(RefCountedUnitTest,NullptrEquality)207 TEST(RefCountedUnitTest, NullptrEquality) {
208 scoped_refptr<SelfAssign> ptr_to_an_instance(new SelfAssign);
209 scoped_refptr<SelfAssign> ptr_to_nullptr;
210
211 EXPECT_NE(nullptr, ptr_to_an_instance);
212 EXPECT_NE(ptr_to_an_instance, nullptr);
213 EXPECT_EQ(nullptr, ptr_to_nullptr);
214 EXPECT_EQ(ptr_to_nullptr, nullptr);
215 }
216
TEST(RefCountedUnitTest,ConvertibleEquality)217 TEST(RefCountedUnitTest, ConvertibleEquality) {
218 scoped_refptr<Derived> p1(new Derived);
219 scoped_refptr<SelfAssign> p2;
220
221 EXPECT_NE(p1, p2);
222 EXPECT_NE(p2, p1);
223
224 p2 = p1;
225
226 EXPECT_EQ(p1, p2);
227 EXPECT_EQ(p2, p1);
228 }
229
TEST(RefCountedUnitTest,MoveAssignment1)230 TEST(RefCountedUnitTest, MoveAssignment1) {
231 ScopedRefPtrCountBase::reset_count();
232
233 {
234 ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase();
235 scoped_refptr<ScopedRefPtrCountBase> p1(raw);
236 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
237 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
238
239 {
240 scoped_refptr<ScopedRefPtrCountBase> p2;
241
242 p2 = std::move(p1);
243 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
244 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
245 EXPECT_EQ(nullptr, p1.get());
246 EXPECT_EQ(raw, p2.get());
247
248 // p2 goes out of scope.
249 }
250 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
251 EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
252
253 // p1 goes out of scope.
254 }
255 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
256 EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
257 }
258
TEST(RefCountedUnitTest,MoveAssignment2)259 TEST(RefCountedUnitTest, MoveAssignment2) {
260 ScopedRefPtrCountBase::reset_count();
261
262 {
263 ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase();
264 scoped_refptr<ScopedRefPtrCountBase> p1;
265 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
266 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
267
268 {
269 scoped_refptr<ScopedRefPtrCountBase> p2(raw);
270 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
271 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
272
273 p1 = std::move(p2);
274 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
275 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
276 EXPECT_EQ(raw, p1.get());
277 EXPECT_EQ(nullptr, p2.get());
278
279 // p2 goes out of scope.
280 }
281 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
282 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
283
284 // p1 goes out of scope.
285 }
286 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
287 EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
288 }
289
TEST(RefCountedUnitTest,MoveAssignmentSameInstance1)290 TEST(RefCountedUnitTest, MoveAssignmentSameInstance1) {
291 ScopedRefPtrCountBase::reset_count();
292
293 {
294 ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase();
295 scoped_refptr<ScopedRefPtrCountBase> p1(raw);
296 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
297 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
298
299 {
300 scoped_refptr<ScopedRefPtrCountBase> p2(p1);
301 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
302 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
303
304 p1 = std::move(p2);
305 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
306 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
307 EXPECT_EQ(raw, p1.get());
308 EXPECT_EQ(nullptr, p2.get());
309
310 // p2 goes out of scope.
311 }
312 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
313 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
314
315 // p1 goes out of scope.
316 }
317 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
318 EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
319 }
320
TEST(RefCountedUnitTest,MoveAssignmentSameInstance2)321 TEST(RefCountedUnitTest, MoveAssignmentSameInstance2) {
322 ScopedRefPtrCountBase::reset_count();
323
324 {
325 ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase();
326 scoped_refptr<ScopedRefPtrCountBase> p1(raw);
327 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
328 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
329
330 {
331 scoped_refptr<ScopedRefPtrCountBase> p2(p1);
332 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
333 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
334
335 p2 = std::move(p1);
336 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
337 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
338 EXPECT_EQ(nullptr, p1.get());
339 EXPECT_EQ(raw, p2.get());
340
341 // p2 goes out of scope.
342 }
343 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
344 EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
345
346 // p1 goes out of scope.
347 }
348 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
349 EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
350 }
351
TEST(RefCountedUnitTest,MoveAssignmentDifferentInstances)352 TEST(RefCountedUnitTest, MoveAssignmentDifferentInstances) {
353 ScopedRefPtrCountBase::reset_count();
354
355 {
356 ScopedRefPtrCountBase *raw1 = new ScopedRefPtrCountBase();
357 scoped_refptr<ScopedRefPtrCountBase> p1(raw1);
358 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
359 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
360
361 {
362 ScopedRefPtrCountBase *raw2 = new ScopedRefPtrCountBase();
363 scoped_refptr<ScopedRefPtrCountBase> p2(raw2);
364 EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
365 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
366
367 p1 = std::move(p2);
368 EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
369 EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
370 EXPECT_EQ(raw2, p1.get());
371 EXPECT_EQ(nullptr, p2.get());
372
373 // p2 goes out of scope.
374 }
375 EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
376 EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
377
378 // p1 goes out of scope.
379 }
380 EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
381 EXPECT_EQ(2, ScopedRefPtrCountBase::destructor_count());
382 }
383
TEST(RefCountedUnitTest,MoveAssignmentDerived)384 TEST(RefCountedUnitTest, MoveAssignmentDerived) {
385 ScopedRefPtrCountBase::reset_count();
386 ScopedRefPtrCountDerived::reset_count();
387
388 {
389 ScopedRefPtrCountBase *raw1 = new ScopedRefPtrCountBase();
390 scoped_refptr<ScopedRefPtrCountBase> p1(raw1);
391 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
392 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
393 EXPECT_EQ(0, ScopedRefPtrCountDerived::constructor_count());
394 EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
395
396 {
397 ScopedRefPtrCountDerived *raw2 = new ScopedRefPtrCountDerived();
398 scoped_refptr<ScopedRefPtrCountDerived> p2(raw2);
399 EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
400 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
401 EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
402 EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
403
404 p1 = std::move(p2);
405 EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
406 EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
407 EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
408 EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
409 EXPECT_EQ(raw2, p1.get());
410 EXPECT_EQ(nullptr, p2.get());
411
412 // p2 goes out of scope.
413 }
414 EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
415 EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
416 EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
417 EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
418
419 // p1 goes out of scope.
420 }
421 EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
422 EXPECT_EQ(2, ScopedRefPtrCountBase::destructor_count());
423 EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
424 EXPECT_EQ(1, ScopedRefPtrCountDerived::destructor_count());
425 }
426
TEST(RefCountedUnitTest,MoveConstructor)427 TEST(RefCountedUnitTest, MoveConstructor) {
428 ScopedRefPtrCountBase::reset_count();
429
430 {
431 ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase();
432 scoped_refptr<ScopedRefPtrCountBase> p1(raw);
433 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
434 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
435
436 {
437 scoped_refptr<ScopedRefPtrCountBase> p2(std::move(p1));
438 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
439 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
440 EXPECT_EQ(nullptr, p1.get());
441 EXPECT_EQ(raw, p2.get());
442
443 // p2 goes out of scope.
444 }
445 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
446 EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
447
448 // p1 goes out of scope.
449 }
450 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
451 EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
452 }
453
TEST(RefCountedUnitTest,MoveConstructorDerived)454 TEST(RefCountedUnitTest, MoveConstructorDerived) {
455 ScopedRefPtrCountBase::reset_count();
456 ScopedRefPtrCountDerived::reset_count();
457
458 {
459 ScopedRefPtrCountDerived *raw1 = new ScopedRefPtrCountDerived();
460 scoped_refptr<ScopedRefPtrCountDerived> p1(raw1);
461 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
462 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
463 EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
464 EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
465
466 {
467 scoped_refptr<ScopedRefPtrCountBase> p2(std::move(p1));
468 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
469 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
470 EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
471 EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
472 EXPECT_EQ(nullptr, p1.get());
473 EXPECT_EQ(raw1, p2.get());
474
475 // p2 goes out of scope.
476 }
477 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
478 EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
479 EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
480 EXPECT_EQ(1, ScopedRefPtrCountDerived::destructor_count());
481
482 // p1 goes out of scope.
483 }
484 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
485 EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
486 EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
487 EXPECT_EQ(1, ScopedRefPtrCountDerived::destructor_count());
488 }
489
TEST(RefCountedUnitTest,TestOverloadResolutionCopy)490 TEST(RefCountedUnitTest, TestOverloadResolutionCopy) {
491 scoped_refptr<Derived> derived(new Derived);
492 scoped_refptr<SelfAssign> expected(derived);
493 EXPECT_EQ(expected, Overloaded(derived));
494
495 scoped_refptr<Other> other(new Other);
496 EXPECT_EQ(other, Overloaded(other));
497 }
498
TEST(RefCountedUnitTest,TestOverloadResolutionMove)499 TEST(RefCountedUnitTest, TestOverloadResolutionMove) {
500 scoped_refptr<Derived> derived(new Derived);
501 scoped_refptr<SelfAssign> expected(derived);
502 EXPECT_EQ(expected, Overloaded(std::move(derived)));
503
504 scoped_refptr<Other> other(new Other);
505 scoped_refptr<Other> other2(other);
506 EXPECT_EQ(other2, Overloaded(std::move(other)));
507 }
508