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 <gtest/gtest.h>
8
9 namespace {
10
11 class SelfAssign : public base::RefCounted<SelfAssign> {
12 protected:
~SelfAssign()13 virtual ~SelfAssign() {}
14
15 private:
16 friend class base::RefCounted<SelfAssign>;
17 };
18
19 class Derived : public SelfAssign {
20 protected:
~Derived()21 ~Derived() override {}
22
23 private:
24 friend class base::RefCounted<Derived>;
25 };
26
27 class CheckDerivedMemberAccess : public scoped_refptr<SelfAssign> {
28 public:
CheckDerivedMemberAccess()29 CheckDerivedMemberAccess() {
30 // This shouldn't compile if we don't have access to the member variable.
31 SelfAssign** pptr = &ptr_;
32 EXPECT_EQ(*pptr, ptr_);
33 }
34 };
35
36 class ScopedRefPtrToSelf : public base::RefCounted<ScopedRefPtrToSelf> {
37 public:
ScopedRefPtrToSelf()38 ScopedRefPtrToSelf() : self_ptr_(this) {}
39
was_destroyed()40 static bool was_destroyed() { return was_destroyed_; }
41
reset_was_destroyed()42 static void reset_was_destroyed() { was_destroyed_ = false; }
43
44 scoped_refptr<ScopedRefPtrToSelf> self_ptr_;
45
46 private:
47 friend class base::RefCounted<ScopedRefPtrToSelf>;
~ScopedRefPtrToSelf()48 ~ScopedRefPtrToSelf() { was_destroyed_ = true; }
49
50 static bool was_destroyed_;
51 };
52
53 bool ScopedRefPtrToSelf::was_destroyed_ = false;
54
55 class ScopedRefPtrCountBase : public base::RefCounted<ScopedRefPtrCountBase> {
56 public:
ScopedRefPtrCountBase()57 ScopedRefPtrCountBase() { ++constructor_count_; }
58
constructor_count()59 static int constructor_count() { return constructor_count_; }
60
destructor_count()61 static int destructor_count() { return destructor_count_; }
62
reset_count()63 static void reset_count() {
64 constructor_count_ = 0;
65 destructor_count_ = 0;
66 }
67
68 protected:
~ScopedRefPtrCountBase()69 virtual ~ScopedRefPtrCountBase() { ++destructor_count_; }
70
71 private:
72 friend class base::RefCounted<ScopedRefPtrCountBase>;
73
74 static int constructor_count_;
75 static int destructor_count_;
76 };
77
78 int ScopedRefPtrCountBase::constructor_count_ = 0;
79 int ScopedRefPtrCountBase::destructor_count_ = 0;
80
81 class ScopedRefPtrCountDerived : public ScopedRefPtrCountBase {
82 public:
ScopedRefPtrCountDerived()83 ScopedRefPtrCountDerived() { ++constructor_count_; }
84
constructor_count()85 static int constructor_count() { return constructor_count_; }
86
destructor_count()87 static int destructor_count() { return destructor_count_; }
88
reset_count()89 static void reset_count() {
90 constructor_count_ = 0;
91 destructor_count_ = 0;
92 }
93
94 protected:
~ScopedRefPtrCountDerived()95 ~ScopedRefPtrCountDerived() override { ++destructor_count_; }
96
97 private:
98 friend class base::RefCounted<ScopedRefPtrCountDerived>;
99
100 static int constructor_count_;
101 static int destructor_count_;
102 };
103
104 int ScopedRefPtrCountDerived::constructor_count_ = 0;
105 int ScopedRefPtrCountDerived::destructor_count_ = 0;
106
107 } // end namespace
108
TEST(RefCountedUnitTest,TestSelfAssignment)109 TEST(RefCountedUnitTest, TestSelfAssignment) {
110 SelfAssign* p = new SelfAssign;
111 scoped_refptr<SelfAssign> var(p);
112 var = var;
113 EXPECT_EQ(var.get(), p);
114 }
115
TEST(RefCountedUnitTest,ScopedRefPtrMemberAccess)116 TEST(RefCountedUnitTest, ScopedRefPtrMemberAccess) {
117 CheckDerivedMemberAccess check;
118 }
119
TEST(RefCountedUnitTest,ScopedRefPtrToSelfPointerAssignment)120 TEST(RefCountedUnitTest, ScopedRefPtrToSelfPointerAssignment) {
121 ScopedRefPtrToSelf::reset_was_destroyed();
122
123 ScopedRefPtrToSelf* check = new ScopedRefPtrToSelf();
124 EXPECT_FALSE(ScopedRefPtrToSelf::was_destroyed());
125 check->self_ptr_ = nullptr;
126 EXPECT_TRUE(ScopedRefPtrToSelf::was_destroyed());
127 }
128
TEST(RefCountedUnitTest,ScopedRefPtrToSelfMoveAssignment)129 TEST(RefCountedUnitTest, ScopedRefPtrToSelfMoveAssignment) {
130 ScopedRefPtrToSelf::reset_was_destroyed();
131
132 ScopedRefPtrToSelf* check = new ScopedRefPtrToSelf();
133 EXPECT_FALSE(ScopedRefPtrToSelf::was_destroyed());
134 // Releasing |check->self_ptr_| will delete |check|.
135 // The move assignment operator must assign |check->self_ptr_| first then
136 // release |check->self_ptr_|.
137 check->self_ptr_ = scoped_refptr<ScopedRefPtrToSelf>();
138 EXPECT_TRUE(ScopedRefPtrToSelf::was_destroyed());
139 }
140
TEST(RefCountedUnitTest,BooleanTesting)141 TEST(RefCountedUnitTest, BooleanTesting) {
142 scoped_refptr<SelfAssign> p;
143 EXPECT_FALSE(p);
144 p = new SelfAssign;
145 EXPECT_TRUE(p);
146 }
147
TEST(RefCountedUnitTest,Equality)148 TEST(RefCountedUnitTest, Equality) {
149 scoped_refptr<SelfAssign> p1(new SelfAssign);
150 scoped_refptr<SelfAssign> p2(new SelfAssign);
151
152 EXPECT_EQ(p1, p1);
153 EXPECT_EQ(p2, p2);
154
155 EXPECT_NE(p1, p2);
156 EXPECT_NE(p2, p1);
157 }
158
TEST(RefCountedUnitTest,ConvertibleEquality)159 TEST(RefCountedUnitTest, ConvertibleEquality) {
160 scoped_refptr<Derived> p1(new Derived);
161 scoped_refptr<SelfAssign> p2;
162
163 EXPECT_NE(p1, p2);
164 EXPECT_NE(p2, p1);
165
166 p2 = p1;
167
168 EXPECT_EQ(p1, p2);
169 EXPECT_EQ(p2, p1);
170 }
171
TEST(RefCountedUnitTest,MoveAssignment1)172 TEST(RefCountedUnitTest, MoveAssignment1) {
173 ScopedRefPtrCountBase::reset_count();
174
175 {
176 ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase();
177 scoped_refptr<ScopedRefPtrCountBase> p1(raw);
178 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
179 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
180
181 {
182 scoped_refptr<ScopedRefPtrCountBase> p2;
183
184 p2 = std::move(p1);
185 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
186 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
187 EXPECT_EQ(nullptr, p1.get());
188 EXPECT_EQ(raw, p2.get());
189
190 // p2 goes out of scope.
191 }
192 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
193 EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
194
195 // p1 goes out of scope.
196 }
197 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
198 EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
199 }
200
TEST(RefCountedUnitTest,MoveAssignment2)201 TEST(RefCountedUnitTest, MoveAssignment2) {
202 ScopedRefPtrCountBase::reset_count();
203
204 {
205 ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase();
206 scoped_refptr<ScopedRefPtrCountBase> p1;
207 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
208 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
209
210 {
211 scoped_refptr<ScopedRefPtrCountBase> p2(raw);
212 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
213 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
214
215 p1 = std::move(p2);
216 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
217 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
218 EXPECT_EQ(raw, p1.get());
219 EXPECT_EQ(nullptr, p2.get());
220
221 // p2 goes out of scope.
222 }
223 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
224 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
225
226 // p1 goes out of scope.
227 }
228 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
229 EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
230 }
231
TEST(RefCountedUnitTest,MoveAssignmentSameInstance1)232 TEST(RefCountedUnitTest, MoveAssignmentSameInstance1) {
233 ScopedRefPtrCountBase::reset_count();
234
235 {
236 ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase();
237 scoped_refptr<ScopedRefPtrCountBase> p1(raw);
238 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
239 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
240
241 {
242 scoped_refptr<ScopedRefPtrCountBase> p2(p1);
243 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
244 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
245
246 p1 = std::move(p2);
247 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
248 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
249 EXPECT_EQ(raw, p1.get());
250 EXPECT_EQ(nullptr, p2.get());
251
252 // p2 goes out of scope.
253 }
254 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
255 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
256
257 // p1 goes out of scope.
258 }
259 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
260 EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
261 }
262
TEST(RefCountedUnitTest,MoveAssignmentSameInstance2)263 TEST(RefCountedUnitTest, MoveAssignmentSameInstance2) {
264 ScopedRefPtrCountBase::reset_count();
265
266 {
267 ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase();
268 scoped_refptr<ScopedRefPtrCountBase> p1(raw);
269 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
270 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
271
272 {
273 scoped_refptr<ScopedRefPtrCountBase> p2(p1);
274 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
275 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
276
277 p2 = std::move(p1);
278 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
279 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
280 EXPECT_EQ(nullptr, p1.get());
281 EXPECT_EQ(raw, p2.get());
282
283 // p2 goes out of scope.
284 }
285 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
286 EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
287
288 // p1 goes out of scope.
289 }
290 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
291 EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
292 }
293
TEST(RefCountedUnitTest,MoveAssignmentDifferentInstances)294 TEST(RefCountedUnitTest, MoveAssignmentDifferentInstances) {
295 ScopedRefPtrCountBase::reset_count();
296
297 {
298 ScopedRefPtrCountBase *raw1 = new ScopedRefPtrCountBase();
299 scoped_refptr<ScopedRefPtrCountBase> p1(raw1);
300 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
301 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
302
303 {
304 ScopedRefPtrCountBase *raw2 = new ScopedRefPtrCountBase();
305 scoped_refptr<ScopedRefPtrCountBase> p2(raw2);
306 EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
307 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
308
309 p1 = std::move(p2);
310 EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
311 EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
312 EXPECT_EQ(raw2, p1.get());
313 EXPECT_EQ(nullptr, p2.get());
314
315 // p2 goes out of scope.
316 }
317 EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
318 EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
319
320 // p1 goes out of scope.
321 }
322 EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
323 EXPECT_EQ(2, ScopedRefPtrCountBase::destructor_count());
324 }
325
TEST(RefCountedUnitTest,MoveAssignmentDerived)326 TEST(RefCountedUnitTest, MoveAssignmentDerived) {
327 ScopedRefPtrCountBase::reset_count();
328 ScopedRefPtrCountDerived::reset_count();
329
330 {
331 ScopedRefPtrCountBase *raw1 = new ScopedRefPtrCountBase();
332 scoped_refptr<ScopedRefPtrCountBase> p1(raw1);
333 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
334 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
335 EXPECT_EQ(0, ScopedRefPtrCountDerived::constructor_count());
336 EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
337
338 {
339 ScopedRefPtrCountDerived *raw2 = new ScopedRefPtrCountDerived();
340 scoped_refptr<ScopedRefPtrCountDerived> p2(raw2);
341 EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
342 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
343 EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
344 EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
345
346 p1 = std::move(p2);
347 EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
348 EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
349 EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
350 EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
351 EXPECT_EQ(raw2, p1.get());
352 EXPECT_EQ(nullptr, p2.get());
353
354 // p2 goes out of scope.
355 }
356 EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
357 EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
358 EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
359 EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
360
361 // p1 goes out of scope.
362 }
363 EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
364 EXPECT_EQ(2, ScopedRefPtrCountBase::destructor_count());
365 EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
366 EXPECT_EQ(1, ScopedRefPtrCountDerived::destructor_count());
367 }
368
TEST(RefCountedUnitTest,MoveConstructor)369 TEST(RefCountedUnitTest, MoveConstructor) {
370 ScopedRefPtrCountBase::reset_count();
371
372 {
373 ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase();
374 scoped_refptr<ScopedRefPtrCountBase> p1(raw);
375 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
376 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
377
378 {
379 scoped_refptr<ScopedRefPtrCountBase> p2(std::move(p1));
380 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
381 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
382 EXPECT_EQ(nullptr, p1.get());
383 EXPECT_EQ(raw, p2.get());
384
385 // p2 goes out of scope.
386 }
387 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
388 EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
389
390 // p1 goes out of scope.
391 }
392 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
393 EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
394 }
395
TEST(RefCountedUnitTest,MoveConstructorDerived)396 TEST(RefCountedUnitTest, MoveConstructorDerived) {
397 ScopedRefPtrCountBase::reset_count();
398 ScopedRefPtrCountDerived::reset_count();
399
400 {
401 ScopedRefPtrCountDerived *raw1 = new ScopedRefPtrCountDerived();
402 scoped_refptr<ScopedRefPtrCountDerived> p1(raw1);
403 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
404 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
405 EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
406 EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
407
408 {
409 scoped_refptr<ScopedRefPtrCountBase> p2(std::move(p1));
410 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
411 EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
412 EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
413 EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
414 EXPECT_EQ(nullptr, p1.get());
415 EXPECT_EQ(raw1, p2.get());
416
417 // p2 goes out of scope.
418 }
419 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
420 EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
421 EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
422 EXPECT_EQ(1, ScopedRefPtrCountDerived::destructor_count());
423
424 // p1 goes out of scope.
425 }
426 EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
427 EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
428 EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
429 EXPECT_EQ(1, ScopedRefPtrCountDerived::destructor_count());
430 }
431
432