1 // Copyright 2016 PDFium 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 "core/fxcrt/retain_ptr.h"
6
7 #include <utility>
8 #include <vector>
9
10 #include "testing/gtest/include/gtest/gtest.h"
11
12 namespace fxcrt {
13 namespace {
14
15 class PseudoRetainable {
16 public:
PseudoRetainable()17 PseudoRetainable() : retain_count_(0), release_count_(0) {}
Retain()18 void Retain() { ++retain_count_; }
Release()19 void Release() { ++release_count_; }
retain_count() const20 int retain_count() const { return retain_count_; }
release_count() const21 int release_count() const { return release_count_; }
22
23 private:
24 int retain_count_;
25 int release_count_;
26 };
27
28 } // namespace
29
TEST(RetainPtr,Null)30 TEST(RetainPtr, Null) {
31 RetainPtr<PseudoRetainable> ptr;
32 EXPECT_EQ(nullptr, ptr.Get());
33 }
34
TEST(RetainPtr,Normal)35 TEST(RetainPtr, Normal) {
36 PseudoRetainable obj;
37 {
38 RetainPtr<PseudoRetainable> ptr(&obj);
39 EXPECT_EQ(&obj, ptr.Get());
40 EXPECT_EQ(1, obj.retain_count());
41 EXPECT_EQ(0, obj.release_count());
42 }
43 EXPECT_EQ(1, obj.retain_count());
44 EXPECT_EQ(1, obj.release_count());
45 }
46
TEST(RetainPtr,CopyCtor)47 TEST(RetainPtr, CopyCtor) {
48 PseudoRetainable obj;
49 {
50 RetainPtr<PseudoRetainable> ptr1(&obj);
51 {
52 RetainPtr<PseudoRetainable> ptr2(ptr1);
53 EXPECT_EQ(2, obj.retain_count());
54 EXPECT_EQ(0, obj.release_count());
55 }
56 EXPECT_EQ(2, obj.retain_count());
57 EXPECT_EQ(1, obj.release_count());
58 }
59 EXPECT_EQ(2, obj.retain_count());
60 EXPECT_EQ(2, obj.release_count());
61 }
62
TEST(RetainPtr,MoveCtor)63 TEST(RetainPtr, MoveCtor) {
64 PseudoRetainable obj;
65 {
66 RetainPtr<PseudoRetainable> ptr1(&obj);
67 {
68 RetainPtr<PseudoRetainable> ptr2(std::move(ptr1));
69 EXPECT_EQ(nullptr, ptr1.Get());
70 EXPECT_EQ(&obj, ptr2.Get());
71 EXPECT_EQ(1, obj.retain_count());
72 EXPECT_EQ(0, obj.release_count());
73 }
74 EXPECT_EQ(1, obj.retain_count());
75 EXPECT_EQ(1, obj.release_count());
76 }
77 EXPECT_EQ(1, obj.retain_count());
78 EXPECT_EQ(1, obj.release_count());
79 }
80
TEST(RetainPtr,ResetNull)81 TEST(RetainPtr, ResetNull) {
82 PseudoRetainable obj;
83 {
84 RetainPtr<PseudoRetainable> ptr(&obj);
85 ptr.Reset();
86 EXPECT_EQ(1, obj.retain_count());
87 EXPECT_EQ(1, obj.release_count());
88 }
89 EXPECT_EQ(1, obj.retain_count());
90 EXPECT_EQ(1, obj.release_count());
91 }
92
TEST(RetainPtr,Reset)93 TEST(RetainPtr, Reset) {
94 PseudoRetainable obj1;
95 PseudoRetainable obj2;
96 {
97 RetainPtr<PseudoRetainable> ptr(&obj1);
98 ptr.Reset(&obj2);
99 EXPECT_EQ(1, obj1.retain_count());
100 EXPECT_EQ(1, obj1.release_count());
101 EXPECT_EQ(1, obj2.retain_count());
102 EXPECT_EQ(0, obj2.release_count());
103 }
104 EXPECT_EQ(1, obj1.retain_count());
105 EXPECT_EQ(1, obj1.release_count());
106 EXPECT_EQ(1, obj2.retain_count());
107 EXPECT_EQ(1, obj2.release_count());
108 }
109
TEST(RetainPtr,Swap)110 TEST(RetainPtr, Swap) {
111 PseudoRetainable obj1;
112 PseudoRetainable obj2;
113 {
114 RetainPtr<PseudoRetainable> ptr1(&obj1);
115 {
116 RetainPtr<PseudoRetainable> ptr2(&obj2);
117 ptr1.Swap(ptr2);
118 EXPECT_EQ(1, obj1.retain_count());
119 EXPECT_EQ(0, obj1.release_count());
120 EXPECT_EQ(1, obj2.retain_count());
121 EXPECT_EQ(0, obj2.release_count());
122 }
123 EXPECT_EQ(1, obj1.retain_count());
124 EXPECT_EQ(1, obj1.release_count());
125 EXPECT_EQ(1, obj2.retain_count());
126 EXPECT_EQ(0, obj2.release_count());
127 }
128 EXPECT_EQ(1, obj1.retain_count());
129 EXPECT_EQ(1, obj1.release_count());
130 EXPECT_EQ(1, obj2.retain_count());
131 EXPECT_EQ(1, obj2.release_count());
132 }
133
TEST(RetainPtr,Leak)134 TEST(RetainPtr, Leak) {
135 PseudoRetainable obj;
136 PseudoRetainable* leak;
137 {
138 RetainPtr<PseudoRetainable> ptr(&obj);
139 leak = ptr.Leak();
140 EXPECT_EQ(1, obj.retain_count());
141 EXPECT_EQ(0, obj.release_count());
142 }
143 EXPECT_EQ(1, obj.retain_count());
144 EXPECT_EQ(0, obj.release_count());
145 {
146 RetainPtr<PseudoRetainable> ptr;
147 ptr.Unleak(leak);
148 EXPECT_EQ(1, obj.retain_count());
149 EXPECT_EQ(0, obj.release_count());
150 }
151 EXPECT_EQ(1, obj.retain_count());
152 EXPECT_EQ(1, obj.release_count());
153 }
154
TEST(RetainPtr,SwapNull)155 TEST(RetainPtr, SwapNull) {
156 PseudoRetainable obj1;
157 {
158 RetainPtr<PseudoRetainable> ptr1(&obj1);
159 {
160 RetainPtr<PseudoRetainable> ptr2;
161 ptr1.Swap(ptr2);
162 EXPECT_FALSE(ptr1);
163 EXPECT_TRUE(ptr2);
164 EXPECT_EQ(1, obj1.retain_count());
165 EXPECT_EQ(0, obj1.release_count());
166 }
167 EXPECT_EQ(1, obj1.retain_count());
168 EXPECT_EQ(1, obj1.release_count());
169 }
170 EXPECT_EQ(1, obj1.retain_count());
171 EXPECT_EQ(1, obj1.release_count());
172 }
173
TEST(RetainPtr,Assign)174 TEST(RetainPtr, Assign) {
175 PseudoRetainable obj;
176 {
177 RetainPtr<PseudoRetainable> ptr(&obj);
178 {
179 RetainPtr<PseudoRetainable> ptr2;
180 ptr2 = ptr;
181 EXPECT_EQ(2, obj.retain_count());
182 EXPECT_EQ(0, obj.release_count());
183 }
184 EXPECT_EQ(2, obj.retain_count());
185 EXPECT_EQ(1, obj.release_count());
186 }
187 EXPECT_EQ(2, obj.retain_count());
188 EXPECT_EQ(2, obj.release_count());
189 }
190
TEST(RetainPtr,MoveAssign)191 TEST(RetainPtr, MoveAssign) {
192 PseudoRetainable obj;
193 {
194 RetainPtr<PseudoRetainable> ptr1(&obj);
195 {
196 RetainPtr<PseudoRetainable> ptr2;
197 EXPECT_EQ(&obj, ptr1.Get());
198 EXPECT_EQ(nullptr, ptr2.Get());
199 ptr2 = std::move(ptr1);
200 EXPECT_EQ(nullptr, ptr1.Get());
201 EXPECT_EQ(&obj, ptr2.Get());
202 EXPECT_EQ(1, obj.retain_count());
203 EXPECT_EQ(0, obj.release_count());
204 }
205 EXPECT_EQ(1, obj.retain_count());
206 EXPECT_EQ(1, obj.release_count());
207 }
208 EXPECT_EQ(1, obj.retain_count());
209 EXPECT_EQ(1, obj.release_count());
210 }
211
TEST(RetainPtr,Equals)212 TEST(RetainPtr, Equals) {
213 PseudoRetainable obj1;
214 PseudoRetainable obj2;
215 RetainPtr<PseudoRetainable> null_ptr1;
216 RetainPtr<PseudoRetainable> obj1_ptr1(&obj1);
217 RetainPtr<PseudoRetainable> obj2_ptr1(&obj2);
218 {
219 RetainPtr<PseudoRetainable> null_ptr2;
220 EXPECT_TRUE(null_ptr1 == null_ptr2);
221
222 RetainPtr<PseudoRetainable> obj1_ptr2(&obj1);
223 EXPECT_TRUE(obj1_ptr1 == obj1_ptr2);
224
225 RetainPtr<PseudoRetainable> obj2_ptr2(&obj2);
226 EXPECT_TRUE(obj2_ptr1 == obj2_ptr2);
227 }
228 EXPECT_FALSE(null_ptr1 == obj1_ptr1);
229 EXPECT_FALSE(null_ptr1 == obj2_ptr1);
230 EXPECT_FALSE(obj1_ptr1 == obj2_ptr1);
231 }
232
TEST(RetainPtr,NotEquals)233 TEST(RetainPtr, NotEquals) {
234 PseudoRetainable obj1;
235 PseudoRetainable obj2;
236 RetainPtr<PseudoRetainable> null_ptr1;
237 RetainPtr<PseudoRetainable> obj1_ptr1(&obj1);
238 RetainPtr<PseudoRetainable> obj2_ptr1(&obj2);
239 {
240 RetainPtr<PseudoRetainable> null_ptr2;
241 RetainPtr<PseudoRetainable> obj1_ptr2(&obj1);
242 RetainPtr<PseudoRetainable> obj2_ptr2(&obj2);
243 EXPECT_FALSE(null_ptr1 != null_ptr2);
244 EXPECT_FALSE(obj1_ptr1 != obj1_ptr2);
245 EXPECT_FALSE(obj2_ptr1 != obj2_ptr2);
246 }
247 EXPECT_TRUE(null_ptr1 != obj1_ptr1);
248 EXPECT_TRUE(null_ptr1 != obj2_ptr1);
249 EXPECT_TRUE(obj1_ptr1 != obj2_ptr1);
250 }
251
TEST(RetainPtr,LessThan)252 TEST(RetainPtr, LessThan) {
253 PseudoRetainable objs[2];
254 RetainPtr<PseudoRetainable> obj1_ptr(&objs[0]);
255 RetainPtr<PseudoRetainable> obj2_ptr(&objs[1]);
256 EXPECT_TRUE(obj1_ptr < obj2_ptr);
257 EXPECT_FALSE(obj2_ptr < obj1_ptr);
258 }
259
TEST(RetainPtr,Bool)260 TEST(RetainPtr, Bool) {
261 PseudoRetainable obj1;
262 RetainPtr<PseudoRetainable> null_ptr;
263 RetainPtr<PseudoRetainable> obj1_ptr(&obj1);
264 bool null_bool = !!null_ptr;
265 bool obj1_bool = !!obj1_ptr;
266 EXPECT_FALSE(null_bool);
267 EXPECT_TRUE(obj1_bool);
268 }
269
TEST(RetainPtr,MakeRetained)270 TEST(RetainPtr, MakeRetained) {
271 auto ptr = pdfium::MakeRetain<Retainable>();
272 EXPECT_TRUE(ptr->HasOneRef());
273 {
274 RetainPtr<Retainable> other = ptr;
275 EXPECT_FALSE(ptr->HasOneRef());
276 }
277 EXPECT_TRUE(ptr->HasOneRef());
278 }
279
TEST(RetainPtr,VectorMove)280 TEST(RetainPtr, VectorMove) {
281 // Proves move ctor is selected by std::vector over copy/delete, this
282 // may require the ctor to be marked "noexcept".
283 PseudoRetainable obj;
284 {
285 RetainPtr<PseudoRetainable> ptr(&obj);
286 std::vector<RetainPtr<PseudoRetainable>> vec1;
287 vec1.push_back(std::move(ptr));
288 EXPECT_EQ(1, obj.retain_count());
289 EXPECT_EQ(0, obj.release_count());
290
291 std::vector<RetainPtr<PseudoRetainable>> vec2 = std::move(vec1);
292 EXPECT_EQ(1, obj.retain_count());
293 EXPECT_EQ(0, obj.release_count());
294
295 vec2.resize(4096);
296 EXPECT_EQ(1, obj.retain_count());
297 EXPECT_EQ(0, obj.release_count());
298 }
299 EXPECT_EQ(1, obj.retain_count());
300 EXPECT_EQ(1, obj.release_count());
301 }
302
303 } // namespace fxcrt
304