1 // Copyright 2016 The PDFium Authors
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 <functional>
8 #include <set>
9 #include <utility>
10 #include <vector>
11
12 #include "testing/gtest/include/gtest/gtest.h"
13 #include "testing/pseudo_retainable.h"
14 #include "third_party/base/containers/contains.h"
15
16 namespace {
17
18 template <typename T, typename C = std::less<T>>
19 class NoLinearSearchSet : public std::set<T, C> {
20 public:
21 typename std::set<T, C>::iterator begin() noexcept = delete;
22 typename std::set<T, C>::const_iterator cbegin() const noexcept = delete;
23 };
24
25 } // namespace
26
27 namespace fxcrt {
28 namespace {
29
30 template <typename T, typename C = std::less<T>>
31 class NoLinearSearchSet : public std::set<T, C> {
32 public:
33 typename std::set<T, C>::iterator begin() noexcept = delete;
34 typename std::set<T, C>::const_iterator cbegin() const noexcept = delete;
35 };
36
37 } // namespace
38
TEST(RetainPtr,DefaultCtor)39 TEST(RetainPtr, DefaultCtor) {
40 RetainPtr<PseudoRetainable> ptr;
41 EXPECT_FALSE(ptr.Get());
42 }
43
TEST(RetainPtr,NullptrCtor)44 TEST(RetainPtr, NullptrCtor) {
45 RetainPtr<PseudoRetainable> ptr(nullptr);
46 EXPECT_FALSE(ptr.Get());
47 }
48
TEST(RetainPtr,RawCtor)49 TEST(RetainPtr, RawCtor) {
50 PseudoRetainable obj;
51 {
52 RetainPtr<PseudoRetainable> ptr(&obj);
53 EXPECT_EQ(&obj, ptr.Get());
54 EXPECT_EQ(1, obj.retain_count());
55 EXPECT_EQ(0, obj.release_count());
56 }
57 EXPECT_EQ(1, obj.retain_count());
58 EXPECT_EQ(1, obj.release_count());
59 }
60
TEST(RetainPtr,CopyCtor)61 TEST(RetainPtr, CopyCtor) {
62 PseudoRetainable obj;
63 {
64 RetainPtr<PseudoRetainable> ptr1(&obj);
65 {
66 RetainPtr<PseudoRetainable> ptr2(ptr1);
67 EXPECT_EQ(2, obj.retain_count());
68 EXPECT_EQ(0, obj.release_count());
69 }
70 EXPECT_EQ(2, obj.retain_count());
71 EXPECT_EQ(1, obj.release_count());
72 }
73 EXPECT_EQ(2, obj.retain_count());
74 EXPECT_EQ(2, obj.release_count());
75 }
76
TEST(RetainPtr,MoveCtor)77 TEST(RetainPtr, MoveCtor) {
78 PseudoRetainable obj;
79 {
80 RetainPtr<PseudoRetainable> ptr1(&obj);
81 {
82 RetainPtr<PseudoRetainable> ptr2(std::move(ptr1));
83 EXPECT_FALSE(ptr1.Get());
84 EXPECT_EQ(&obj, ptr2.Get());
85 EXPECT_EQ(1, obj.retain_count());
86 EXPECT_EQ(0, obj.release_count());
87 }
88 EXPECT_EQ(1, obj.retain_count());
89 EXPECT_EQ(1, obj.release_count());
90 }
91 EXPECT_EQ(1, obj.retain_count());
92 EXPECT_EQ(1, obj.release_count());
93 }
94
TEST(RetainPtr,CopyConversionCtor)95 TEST(RetainPtr, CopyConversionCtor) {
96 PseudoRetainable obj;
97 {
98 RetainPtr<PseudoRetainable> ptr1(&obj);
99 {
100 RetainPtr<const PseudoRetainable> ptr2(ptr1);
101 EXPECT_EQ(2, obj.retain_count());
102 EXPECT_EQ(0, obj.release_count());
103 }
104 EXPECT_EQ(2, obj.retain_count());
105 EXPECT_EQ(1, obj.release_count());
106 }
107 EXPECT_EQ(2, obj.retain_count());
108 EXPECT_EQ(2, obj.release_count());
109 }
110
TEST(RetainPtr,MoveConversionCtor)111 TEST(RetainPtr, MoveConversionCtor) {
112 PseudoRetainable obj;
113 {
114 RetainPtr<PseudoRetainable> ptr1(&obj);
115 {
116 RetainPtr<const PseudoRetainable> ptr2(std::move(ptr1));
117 EXPECT_FALSE(ptr1.Get());
118 EXPECT_EQ(&obj, ptr2.Get());
119 EXPECT_EQ(1, obj.retain_count());
120 EXPECT_EQ(0, obj.release_count());
121 }
122 EXPECT_EQ(1, obj.retain_count());
123 EXPECT_EQ(1, obj.release_count());
124 }
125 EXPECT_EQ(1, obj.retain_count());
126 EXPECT_EQ(1, obj.release_count());
127 }
128
TEST(RetainPtr,NullptrAssign)129 TEST(RetainPtr, NullptrAssign) {
130 PseudoRetainable obj;
131 RetainPtr<PseudoRetainable> ptr(&obj);
132 ptr = nullptr;
133 EXPECT_FALSE(ptr);
134 }
135
TEST(RetainPtr,RawAssign)136 TEST(RetainPtr, RawAssign) {
137 PseudoRetainable obj;
138 RetainPtr<PseudoRetainable> ptr;
139 ptr = pdfium::WrapRetain(&obj);
140 EXPECT_EQ(&obj, ptr);
141 }
142
TEST(RetainPtr,CopyAssign)143 TEST(RetainPtr, CopyAssign) {
144 PseudoRetainable obj;
145 {
146 RetainPtr<PseudoRetainable> ptr(&obj);
147 {
148 RetainPtr<PseudoRetainable> ptr2;
149 ptr2 = ptr;
150 EXPECT_EQ(2, obj.retain_count());
151 EXPECT_EQ(0, obj.release_count());
152 }
153 {
154 // Test assignment from wrapped underlying type.
155 RetainPtr<PseudoRetainable> ptr2;
156 ptr2 = pdfium::WrapRetain(ptr.Get());
157 EXPECT_EQ(3, obj.retain_count());
158 EXPECT_EQ(1, obj.release_count());
159 }
160 EXPECT_EQ(3, obj.retain_count());
161 EXPECT_EQ(2, obj.release_count());
162 }
163 EXPECT_EQ(3, obj.retain_count());
164 EXPECT_EQ(3, obj.release_count());
165 }
166
TEST(RetainPtr,MoveAssign)167 TEST(RetainPtr, MoveAssign) {
168 PseudoRetainable obj;
169 {
170 RetainPtr<PseudoRetainable> ptr1(&obj);
171 {
172 RetainPtr<PseudoRetainable> ptr2;
173 EXPECT_EQ(&obj, ptr1.Get());
174 EXPECT_FALSE(ptr2.Get());
175 ptr2 = std::move(ptr1);
176 EXPECT_FALSE(ptr1.Get());
177 EXPECT_EQ(&obj, ptr2.Get());
178 EXPECT_EQ(1, obj.retain_count());
179 EXPECT_EQ(0, obj.release_count());
180 }
181 EXPECT_EQ(1, obj.retain_count());
182 EXPECT_EQ(1, obj.release_count());
183 }
184 EXPECT_EQ(1, obj.retain_count());
185 EXPECT_EQ(1, obj.release_count());
186 }
187
TEST(RetainPtr,CopyConvertAssign)188 TEST(RetainPtr, CopyConvertAssign) {
189 PseudoRetainable obj;
190 {
191 RetainPtr<PseudoRetainable> ptr(&obj);
192 {
193 RetainPtr<const PseudoRetainable> ptr2;
194 ptr2 = ptr;
195 EXPECT_EQ(2, obj.retain_count());
196 EXPECT_EQ(0, obj.release_count());
197 }
198 {
199 // Test assignment from wrapped underlying type.
200 RetainPtr<const PseudoRetainable> ptr2;
201 ptr2 = pdfium::WrapRetain(ptr.Get());
202 EXPECT_EQ(3, obj.retain_count());
203 EXPECT_EQ(1, obj.release_count());
204 }
205 EXPECT_EQ(3, obj.retain_count());
206 EXPECT_EQ(2, obj.release_count());
207 }
208 EXPECT_EQ(3, obj.retain_count());
209 EXPECT_EQ(3, obj.release_count());
210 }
211
TEST(RetainPtr,MoveConvertAssign)212 TEST(RetainPtr, MoveConvertAssign) {
213 PseudoRetainable obj;
214 {
215 RetainPtr<PseudoRetainable> ptr1(&obj);
216 {
217 RetainPtr<const PseudoRetainable> ptr2;
218 ptr2 = std::move(ptr1);
219 EXPECT_FALSE(ptr1);
220 EXPECT_EQ(&obj, ptr2.Get());
221 EXPECT_EQ(1, obj.retain_count());
222 EXPECT_EQ(0, obj.release_count());
223 }
224 EXPECT_EQ(1, obj.retain_count());
225 EXPECT_EQ(1, obj.release_count());
226 }
227 EXPECT_EQ(1, obj.retain_count());
228 EXPECT_EQ(1, obj.release_count());
229 }
230
TEST(RetainPtr,AmbiguousExpression)231 TEST(RetainPtr, AmbiguousExpression) {
232 class A : public Retainable {};
233 class B : public A {};
234
235 // Test passes if it compiles without error.
236 RetainPtr<A> var = (0) ? pdfium::MakeRetain<A>() : pdfium::MakeRetain<B>();
237 EXPECT_TRUE(var);
238 }
239
TEST(RetainPtr,ResetNull)240 TEST(RetainPtr, ResetNull) {
241 PseudoRetainable obj;
242 {
243 RetainPtr<PseudoRetainable> ptr(&obj);
244 ptr.Reset();
245 EXPECT_EQ(1, obj.retain_count());
246 EXPECT_EQ(1, obj.release_count());
247 }
248 EXPECT_EQ(1, obj.retain_count());
249 EXPECT_EQ(1, obj.release_count());
250 }
251
TEST(RetainPtr,Reset)252 TEST(RetainPtr, Reset) {
253 PseudoRetainable obj1;
254 PseudoRetainable obj2;
255 {
256 RetainPtr<PseudoRetainable> ptr(&obj1);
257 ptr.Reset(&obj2);
258 EXPECT_EQ(1, obj1.retain_count());
259 EXPECT_EQ(1, obj1.release_count());
260 EXPECT_EQ(1, obj2.retain_count());
261 EXPECT_EQ(0, obj2.release_count());
262 }
263 EXPECT_EQ(1, obj1.retain_count());
264 EXPECT_EQ(1, obj1.release_count());
265 EXPECT_EQ(1, obj2.retain_count());
266 EXPECT_EQ(1, obj2.release_count());
267 }
268
TEST(RetainPtr,Swap)269 TEST(RetainPtr, Swap) {
270 PseudoRetainable obj1;
271 PseudoRetainable obj2;
272 {
273 RetainPtr<PseudoRetainable> ptr1(&obj1);
274 {
275 RetainPtr<PseudoRetainable> ptr2(&obj2);
276 ptr1.Swap(ptr2);
277 EXPECT_EQ(1, obj1.retain_count());
278 EXPECT_EQ(0, obj1.release_count());
279 EXPECT_EQ(1, obj2.retain_count());
280 EXPECT_EQ(0, obj2.release_count());
281 }
282 EXPECT_EQ(1, obj1.retain_count());
283 EXPECT_EQ(1, obj1.release_count());
284 EXPECT_EQ(1, obj2.retain_count());
285 EXPECT_EQ(0, obj2.release_count());
286 }
287 EXPECT_EQ(1, obj1.retain_count());
288 EXPECT_EQ(1, obj1.release_count());
289 EXPECT_EQ(1, obj2.retain_count());
290 EXPECT_EQ(1, obj2.release_count());
291 }
292
TEST(RetainPtr,Leak)293 TEST(RetainPtr, Leak) {
294 PseudoRetainable obj;
295 PseudoRetainable* leak;
296 {
297 RetainPtr<PseudoRetainable> ptr(&obj);
298 leak = ptr.Leak();
299 EXPECT_EQ(1, obj.retain_count());
300 EXPECT_EQ(0, obj.release_count());
301 }
302 EXPECT_EQ(1, obj.retain_count());
303 EXPECT_EQ(0, obj.release_count());
304 {
305 RetainPtr<PseudoRetainable> ptr;
306 ptr.Unleak(leak);
307 EXPECT_EQ(1, obj.retain_count());
308 EXPECT_EQ(0, obj.release_count());
309 }
310 EXPECT_EQ(1, obj.retain_count());
311 EXPECT_EQ(1, obj.release_count());
312 }
313
TEST(RetainPtr,SwapNull)314 TEST(RetainPtr, SwapNull) {
315 PseudoRetainable obj1;
316 {
317 RetainPtr<PseudoRetainable> ptr1(&obj1);
318 {
319 RetainPtr<PseudoRetainable> ptr2;
320 ptr1.Swap(ptr2);
321 EXPECT_FALSE(ptr1);
322 EXPECT_TRUE(ptr2);
323 EXPECT_EQ(1, obj1.retain_count());
324 EXPECT_EQ(0, obj1.release_count());
325 }
326 EXPECT_EQ(1, obj1.retain_count());
327 EXPECT_EQ(1, obj1.release_count());
328 }
329 EXPECT_EQ(1, obj1.retain_count());
330 EXPECT_EQ(1, obj1.release_count());
331 }
332
TEST(RetainPtr,Equals)333 TEST(RetainPtr, Equals) {
334 PseudoRetainable obj1;
335 PseudoRetainable obj2;
336 RetainPtr<PseudoRetainable> null_ptr1;
337 RetainPtr<PseudoRetainable> obj1_ptr1(&obj1);
338 RetainPtr<PseudoRetainable> obj2_ptr1(&obj2);
339 {
340 RetainPtr<PseudoRetainable> null_ptr2;
341 EXPECT_TRUE(null_ptr1 == null_ptr2);
342 EXPECT_TRUE(null_ptr1 == nullptr);
343
344 RetainPtr<PseudoRetainable> obj1_ptr2(&obj1);
345 EXPECT_TRUE(obj1_ptr1 == obj1_ptr2);
346 EXPECT_TRUE(obj1_ptr2 == &obj1);
347
348 RetainPtr<PseudoRetainable> obj2_ptr2(&obj2);
349 EXPECT_TRUE(obj2_ptr1 == obj2_ptr2);
350 }
351 EXPECT_FALSE(null_ptr1 == obj1_ptr1);
352 EXPECT_FALSE(null_ptr1 == obj2_ptr1);
353 EXPECT_FALSE(obj1_ptr1 == obj2_ptr1);
354 }
355
TEST(RetainPtr,EqualsReflexive)356 TEST(RetainPtr, EqualsReflexive) {
357 PseudoRetainable obj1;
358 PseudoRetainable obj2;
359 RetainPtr<PseudoRetainable> obj1_ptr(&obj1);
360 RetainPtr<PseudoRetainable> obj2_ptr(&obj2);
361 EXPECT_TRUE(&obj1 == obj1_ptr);
362 EXPECT_FALSE(&obj1 == obj2_ptr);
363 EXPECT_FALSE(&obj2 == obj1_ptr);
364 EXPECT_TRUE(&obj2 == obj2_ptr);
365 }
366
TEST(RetainPtr,NotEquals)367 TEST(RetainPtr, NotEquals) {
368 PseudoRetainable obj1;
369 PseudoRetainable obj2;
370 RetainPtr<PseudoRetainable> null_ptr1;
371 RetainPtr<PseudoRetainable> obj1_ptr1(&obj1);
372 RetainPtr<PseudoRetainable> obj2_ptr1(&obj2);
373 {
374 RetainPtr<PseudoRetainable> null_ptr2;
375 RetainPtr<PseudoRetainable> obj1_ptr2(&obj1);
376 RetainPtr<PseudoRetainable> obj2_ptr2(&obj2);
377 EXPECT_FALSE(null_ptr1 != null_ptr2);
378 EXPECT_FALSE(obj1_ptr1 != obj1_ptr2);
379 EXPECT_FALSE(obj2_ptr1 != obj2_ptr2);
380 }
381 EXPECT_TRUE(null_ptr1 != obj1_ptr1);
382 EXPECT_TRUE(null_ptr1 != obj2_ptr1);
383 EXPECT_TRUE(obj1_ptr1 != obj2_ptr1);
384 }
385
TEST(RetainPtr,NotEqualsReflexive)386 TEST(RetainPtr, NotEqualsReflexive) {
387 PseudoRetainable obj1;
388 PseudoRetainable obj2;
389 RetainPtr<PseudoRetainable> obj1_ptr(&obj1);
390 RetainPtr<PseudoRetainable> obj2_ptr(&obj2);
391 EXPECT_FALSE(&obj1 != obj1_ptr);
392 EXPECT_TRUE(&obj1 != obj2_ptr);
393 EXPECT_TRUE(&obj2 != obj1_ptr);
394 EXPECT_FALSE(&obj2 != obj2_ptr);
395 }
396
TEST(RetainPtr,LessThan)397 TEST(RetainPtr, LessThan) {
398 PseudoRetainable objs[2];
399 RetainPtr<PseudoRetainable> obj1_ptr(&objs[0]);
400 RetainPtr<PseudoRetainable> obj2_ptr(&objs[1]);
401 EXPECT_TRUE(obj1_ptr < obj2_ptr);
402 EXPECT_FALSE(obj2_ptr < obj1_ptr);
403 }
404
TEST(RetainPtr,Bool)405 TEST(RetainPtr, Bool) {
406 PseudoRetainable obj1;
407 RetainPtr<PseudoRetainable> null_ptr;
408 RetainPtr<PseudoRetainable> obj1_ptr(&obj1);
409 bool null_bool = !!null_ptr;
410 bool obj1_bool = !!obj1_ptr;
411 EXPECT_FALSE(null_bool);
412 EXPECT_TRUE(obj1_bool);
413 }
414
TEST(RetainPtr,MakeRetained)415 TEST(RetainPtr, MakeRetained) {
416 auto ptr = pdfium::MakeRetain<Retainable>();
417 EXPECT_TRUE(ptr->HasOneRef());
418 {
419 RetainPtr<Retainable> other = ptr;
420 EXPECT_FALSE(ptr->HasOneRef());
421 }
422 EXPECT_TRUE(ptr->HasOneRef());
423 }
424
TEST(RetainPtr,VectorMove)425 TEST(RetainPtr, VectorMove) {
426 // Proves move ctor is selected by std::vector over copy/delete, this
427 // may require the ctor to be marked "noexcept".
428 PseudoRetainable obj;
429 {
430 RetainPtr<PseudoRetainable> ptr(&obj);
431 std::vector<RetainPtr<PseudoRetainable>> vec1;
432 vec1.push_back(std::move(ptr));
433 EXPECT_EQ(1, obj.retain_count());
434 EXPECT_EQ(0, obj.release_count());
435
436 std::vector<RetainPtr<PseudoRetainable>> vec2 = std::move(vec1);
437 EXPECT_EQ(1, obj.retain_count());
438 EXPECT_EQ(0, obj.release_count());
439
440 vec2.resize(4096);
441 EXPECT_EQ(1, obj.retain_count());
442 EXPECT_EQ(0, obj.release_count());
443 }
444 EXPECT_EQ(1, obj.retain_count());
445 EXPECT_EQ(1, obj.release_count());
446 }
447
TEST(RetainPtr,SetContains)448 TEST(RetainPtr, SetContains) {
449 // Makes sure pdfium::Contains() works the same way with raw pointers and
450 // RetainPtrs for containers that use find().
451 PseudoRetainable obj1;
452 PseudoRetainable obj2;
453 RetainPtr<PseudoRetainable> ptr1(&obj1);
454 RetainPtr<PseudoRetainable> ptr2(&obj2);
455 RetainPtr<const PseudoRetainable> const_ptr1(&obj1);
456 RetainPtr<const PseudoRetainable> const_ptr2(&obj2);
457 NoLinearSearchSet<RetainPtr<const PseudoRetainable>, std::less<>> the_set;
458
459 // Intially, two smart pointers to each object.
460 EXPECT_EQ(2, obj1.retain_count());
461 EXPECT_EQ(0, obj1.release_count());
462 EXPECT_EQ(2, obj2.retain_count());
463 EXPECT_EQ(0, obj2.release_count());
464
465 // Passed by const-ref, increment on copy into set's data structure.
466 the_set.insert(const_ptr1);
467 EXPECT_EQ(3, obj1.retain_count());
468 EXPECT_EQ(0, obj1.release_count());
469 EXPECT_EQ(2, obj2.retain_count());
470 EXPECT_EQ(0, obj2.release_count());
471
472 // None of the following should cause any churn.
473 EXPECT_NE(the_set.end(), the_set.find(&obj1));
474 EXPECT_EQ(the_set.end(), the_set.find(&obj2));
475 EXPECT_TRUE(pdfium::Contains(the_set, &obj1));
476 EXPECT_FALSE(pdfium::Contains(the_set, &obj2));
477 EXPECT_EQ(3, obj1.retain_count());
478 EXPECT_EQ(0, obj1.release_count());
479 EXPECT_EQ(2, obj2.retain_count());
480 EXPECT_EQ(0, obj2.release_count());
481
482 EXPECT_NE(the_set.end(), the_set.find(const_ptr1));
483 EXPECT_EQ(the_set.end(), the_set.find(const_ptr2));
484 EXPECT_TRUE(pdfium::Contains(the_set, const_ptr1));
485 EXPECT_FALSE(pdfium::Contains(the_set, const_ptr2));
486 EXPECT_EQ(3, obj1.retain_count());
487 EXPECT_EQ(0, obj1.release_count());
488 EXPECT_EQ(2, obj2.retain_count());
489 EXPECT_EQ(0, obj2.release_count());
490
491 // These involve const-removing conversions which seem to churn.
492 EXPECT_NE(the_set.end(), the_set.find(ptr1));
493 EXPECT_EQ(the_set.end(), the_set.find(ptr2));
494 EXPECT_TRUE(pdfium::Contains(the_set, ptr1));
495 EXPECT_FALSE(pdfium::Contains(the_set, ptr2));
496 EXPECT_EQ(5, obj1.retain_count());
497 EXPECT_EQ(2, obj1.release_count());
498 EXPECT_EQ(4, obj2.retain_count());
499 EXPECT_EQ(2, obj2.release_count());
500 }
501
TEST(RetainPtr,VectorContains)502 TEST(RetainPtr, VectorContains) {
503 // Makes sure pdfium::Contains() works the same way with raw pointers and
504 // RetainPtrs. for containers that use begin()/end().
505 PseudoRetainable obj1;
506 PseudoRetainable obj2;
507 std::vector<const PseudoRetainable*> vec;
508 vec.push_back(&obj1);
509 EXPECT_TRUE(pdfium::Contains(vec, &obj1));
510 EXPECT_FALSE(pdfium::Contains(vec, &obj2));
511
512 RetainPtr<PseudoRetainable> ptr1(&obj1);
513 RetainPtr<PseudoRetainable> ptr2(&obj2);
514 EXPECT_TRUE(pdfium::Contains(vec, ptr1));
515 EXPECT_FALSE(pdfium::Contains(vec, ptr2));
516
517 RetainPtr<const PseudoRetainable> const_ptr1(&obj1);
518 RetainPtr<const PseudoRetainable> const_ptr2(&obj2);
519 EXPECT_TRUE(pdfium::Contains(vec, const_ptr1));
520 EXPECT_FALSE(pdfium::Contains(vec, const_ptr2));
521 }
522
523 } // namespace fxcrt
524