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