xref: /aosp_15_r20/external/pdfium/core/fxcrt/retain_ptr_unittest.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
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