1 // Copyright 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.
5 #include "skia/ext/refptr.h"
7 #include "testing/gtest/include/gtest/gtest.h"
12 TEST(RefPtrTest
, ReferenceCounting
) {
13 SkRefCnt
* ref
= new SkRefCnt();
14 EXPECT_TRUE(ref
->unique());
17 // Adopt the reference from the caller on creation.
18 RefPtr
<SkRefCnt
> refptr1
= AdoptRef(ref
);
19 EXPECT_TRUE(ref
->unique());
20 EXPECT_TRUE(refptr1
->unique());
22 EXPECT_EQ(ref
, &*refptr1
);
23 EXPECT_EQ(ref
, refptr1
.get());
26 // Take a second reference for the second instance.
27 RefPtr
<SkRefCnt
> refptr2(refptr1
);
28 EXPECT_FALSE(ref
->unique());
30 RefPtr
<SkRefCnt
> refptr3
;
31 EXPECT_FALSE(refptr3
);
33 // Take a third reference for the third instance.
35 EXPECT_FALSE(ref
->unique());
37 // Same object, so should have the same refcount.
39 EXPECT_FALSE(ref
->unique());
41 // Drop the object from refptr2, so it should lose its reference.
44 EXPECT_FALSE(ref
->unique());
46 EXPECT_FALSE(refptr2
);
47 EXPECT_EQ(nullptr, refptr2
.get());
50 EXPECT_FALSE(refptr3
->unique());
51 EXPECT_EQ(ref
, &*refptr3
);
52 EXPECT_EQ(ref
, refptr3
.get());
55 // Drop a reference when the third object is destroyed.
56 EXPECT_TRUE(ref
->unique());
60 TEST(RefPtrTest
, Construct
) {
61 SkRefCnt
* ref
= new SkRefCnt();
62 EXPECT_TRUE(ref
->unique());
64 // Adopt the reference from the caller on creation.
65 RefPtr
<SkRefCnt
> refptr1(AdoptRef(ref
));
66 EXPECT_TRUE(ref
->unique());
67 EXPECT_TRUE(refptr1
->unique());
69 EXPECT_EQ(ref
, &*refptr1
);
70 EXPECT_EQ(ref
, refptr1
.get());
72 RefPtr
<SkRefCnt
> refptr2(refptr1
);
73 EXPECT_FALSE(ref
->unique());
76 TEST(RefPtrTest
, DeclareAndAssign
) {
77 SkRefCnt
* ref
= new SkRefCnt();
78 EXPECT_TRUE(ref
->unique());
80 // Adopt the reference from the caller on creation.
81 RefPtr
<SkRefCnt
> refptr1
= AdoptRef(ref
);
82 EXPECT_TRUE(ref
->unique());
83 EXPECT_TRUE(refptr1
->unique());
85 EXPECT_EQ(ref
, &*refptr1
);
86 EXPECT_EQ(ref
, refptr1
.get());
88 RefPtr
<SkRefCnt
> refptr2
= refptr1
;
89 EXPECT_FALSE(ref
->unique());
92 TEST(RefPtrTest
, Assign
) {
93 SkRefCnt
* ref
= new SkRefCnt();
94 EXPECT_TRUE(ref
->unique());
96 // Adopt the reference from the caller on creation.
97 RefPtr
<SkRefCnt
> refptr1
;
98 refptr1
= AdoptRef(ref
);
99 EXPECT_TRUE(ref
->unique());
100 EXPECT_TRUE(refptr1
->unique());
102 EXPECT_EQ(ref
, &*refptr1
);
103 EXPECT_EQ(ref
, refptr1
.get());
105 RefPtr
<SkRefCnt
> refptr2
;
107 EXPECT_FALSE(ref
->unique());
110 class Subclass
: public SkRefCnt
{};
112 TEST(RefPtrTest
, Upcast
) {
113 RefPtr
<Subclass
> child
= AdoptRef(new Subclass());
114 EXPECT_TRUE(child
->unique());
116 RefPtr
<SkRefCnt
> parent
= child
;
120 EXPECT_FALSE(child
->unique());
121 EXPECT_FALSE(parent
->unique());
124 // Counts the number of ref/unref operations (which require atomic operations)
126 class RefCountCounter
: public SkRefCnt
{
129 ref_count_changes_
++;
133 ref_count_changes_
++;
136 int ref_count_changes() const { return ref_count_changes_
; }
137 void ResetRefCountChanges() { ref_count_changes_
= 0; }
140 mutable int ref_count_changes_
= 0;
143 TEST(RefPtrTest
, ConstructionFromTemporary
) {
144 // No ref count changes to move temporary into a local.
145 RefPtr
<RefCountCounter
> object
= skia::AdoptRef(new RefCountCounter
);
146 EXPECT_EQ(0, object
->ref_count_changes());
148 // Only one change to share the pointer.
149 object
->ResetRefCountChanges();
150 RefPtr
<RefCountCounter
> shared
= skia::SharePtr(object
.get());
151 EXPECT_EQ(1, object
->ref_count_changes());
153 // Two ref count changes for the extra ref when passed as an argument, but no
155 object
->ResetRefCountChanges();
156 auto do_nothing
= [](RefPtr
<RefCountCounter
>) {};
158 EXPECT_EQ(2, object
->ref_count_changes());
160 // No ref count changes when passing a newly adopted ref as an argument.
161 auto lambda
= [](RefPtr
<RefCountCounter
> arg
) {
162 EXPECT_EQ(0, arg
->ref_count_changes());
164 lambda(skia::AdoptRef(new RefCountCounter
));
167 TEST(RefPtrTest
, AssignmentFromTemporary
) {
168 // No ref count changes to move temporary into a local.
169 RefPtr
<RefCountCounter
> object
;
170 object
= skia::AdoptRef(new RefCountCounter
);
171 EXPECT_EQ(0, object
->ref_count_changes());
173 // Only one change to share the pointer.
174 object
->ResetRefCountChanges();
175 RefPtr
<RefCountCounter
> shared
;
176 shared
= skia::SharePtr(object
.get());
177 EXPECT_EQ(1, object
->ref_count_changes());
180 TEST(RefPtrTest
, PassIntoArguments
) {
181 // No ref count changes when passing an argument with Pass().
182 RefPtr
<RefCountCounter
> object
= skia::AdoptRef(new RefCountCounter
);
183 RefPtr
<RefCountCounter
> object2
= object
.Pass();
184 auto lambda
= [](RefPtr
<RefCountCounter
> arg
) {
185 EXPECT_EQ(0, arg
->ref_count_changes());
187 lambda(object2
.Pass());
190 class DestructionNotifier
: public SkRefCnt
{
192 DestructionNotifier(bool* flag
) : flag_(flag
) {}
193 ~DestructionNotifier() override
{ *flag_
= true; }
199 TEST(RefPtrTest
, PassIntoSelf
) {
200 bool is_destroyed
= false;
201 RefPtr
<DestructionNotifier
> object
=
202 skia::AdoptRef(new DestructionNotifier(&is_destroyed
));
203 object
= object
.Pass();
204 ASSERT_FALSE(is_destroyed
);
205 EXPECT_TRUE(object
->unique());
208 TEST(RefPtrTest
, Nullptr
) {
209 RefPtr
<SkRefCnt
> null(nullptr);
212 bool is_destroyed
= false;
213 RefPtr
<DestructionNotifier
> destroy_me
=
214 skia::AdoptRef(new DestructionNotifier(&is_destroyed
));
215 destroy_me
= nullptr;
216 EXPECT_TRUE(is_destroyed
);
217 EXPECT_FALSE(destroy_me
);
219 // Check that returning nullptr from a function correctly causes an implicit
221 auto lambda
= []() -> RefPtr
<SkRefCnt
> { return nullptr; };
222 RefPtr
<SkRefCnt
> returned
= lambda();
223 EXPECT_FALSE(returned
);