1 // Copyright 2016 The Fuchsia 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 <fbl/alloc_checker.h>
6 #include <fbl/ref_counted.h>
7 #include <fbl/ref_ptr.h>
8 #include <stdio.h>
9 #include <unittest/unittest.h>
10
11 #include <utility>
12
13 namespace {
14
15 class RefCallCounter {
16 public:
17 RefCallCounter();
18 ~RefCallCounter();
19
20 void AddRef();
21 bool Release();
22
Adopt()23 void Adopt() {}
24
add_ref_calls() const25 int add_ref_calls() const { return add_ref_calls_; }
release_calls() const26 int release_calls() const { return release_calls_; }
27
destroy_calls()28 static int destroy_calls() { return destroy_calls_; }
operator delete(void * ptr)29 static void operator delete(void* ptr) {}
30
31 private:
32 int add_ref_calls_;
33 int release_calls_;
34
35
36 static int destroy_calls_;
37 };
38
39 int RefCallCounter::destroy_calls_ = 0u;
40
RefCallCounter()41 RefCallCounter::RefCallCounter()
42 : add_ref_calls_(0u), release_calls_(0u) {}
43
~RefCallCounter()44 RefCallCounter::~RefCallCounter() {
45 destroy_calls_++;
46 }
47
AddRef()48 void RefCallCounter::AddRef() {
49 add_ref_calls_++;
50 }
Release()51 bool RefCallCounter::Release() {
52 release_calls_++;
53 return add_ref_calls_ == release_calls_;
54 }
55
56 static_assert(fbl::is_standard_layout<fbl::RefPtr<RefCallCounter>>::value,
57 "fbl::RefPtr<T>'s should have a standard layout.");
58
ref_ptr_test()59 static bool ref_ptr_test() {
60 BEGIN_TEST;
61 using RefCallPtr = fbl::RefPtr<RefCallCounter>;
62
63 RefCallCounter counter;
64 RefCallPtr ptr = fbl::AdoptRef<RefCallCounter>(&counter);
65
66 EXPECT_TRUE(&counter == ptr.get(), ".get() should point to object");
67 EXPECT_TRUE(static_cast<bool>(ptr), "operator bool");
68 EXPECT_TRUE(&counter == &(*ptr), "operator*");
69
70 // Adoption should not manipulate the refcount.
71 EXPECT_EQ(0, counter.add_ref_calls());
72 EXPECT_EQ(0, counter.release_calls());
73 EXPECT_EQ(0, RefCallCounter::destroy_calls());
74
75 {
76 RefCallPtr ptr2 = ptr;
77
78 // Copying to a new RefPtr should call add once.
79 EXPECT_EQ(1, counter.add_ref_calls());
80 EXPECT_EQ(0, counter.release_calls());
81 EXPECT_EQ(0, RefCallCounter::destroy_calls());
82 }
83 // Destroying the new RefPtr should release once.
84 EXPECT_EQ(1, counter.add_ref_calls());
85 EXPECT_EQ(1, counter.release_calls());
86 EXPECT_EQ(1, RefCallCounter::destroy_calls());
87
88 {
89 RefCallPtr ptr2;
90
91 EXPECT_TRUE(!static_cast<bool>(ptr2));
92
93 ptr.swap(ptr2);
94
95 // Swapping shouldn't cause any add or release calls, but should update
96 // values.
97 EXPECT_EQ(1, counter.add_ref_calls());
98 EXPECT_EQ(1, counter.release_calls());
99 EXPECT_EQ(1, RefCallCounter::destroy_calls());
100
101 EXPECT_TRUE(!static_cast<bool>(ptr));
102 EXPECT_TRUE(&counter == ptr2.get());
103
104 ptr2.swap(ptr);
105 }
106
107 EXPECT_EQ(1, counter.add_ref_calls());
108 EXPECT_EQ(1, counter.release_calls());
109 EXPECT_EQ(1, RefCallCounter::destroy_calls());
110
111 {
112 RefCallPtr ptr2 = std::move(ptr);
113
114 // Moving shouldn't cause any add or release but should update values.
115 EXPECT_EQ(1, counter.add_ref_calls());
116 EXPECT_EQ(1, counter.release_calls());
117 EXPECT_EQ(1, RefCallCounter::destroy_calls());
118
119 EXPECT_FALSE(static_cast<bool>(ptr));
120 EXPECT_TRUE(&counter == ptr2.get());
121
122 ptr2.swap(ptr);
123 }
124
125 // Reset should calls release and clear out the pointer.
126 ptr.reset(nullptr);
127 EXPECT_EQ(1, counter.add_ref_calls());
128 EXPECT_EQ(2, counter.release_calls());
129 EXPECT_EQ(1, RefCallCounter::destroy_calls());
130 EXPECT_FALSE(static_cast<bool>(ptr));
131 EXPECT_FALSE(ptr.get());
132
133 END_TEST;
134 }
135
ref_ptr_compare_test()136 static bool ref_ptr_compare_test() {
137 BEGIN_TEST;
138 using RefCallPtr = fbl::RefPtr<RefCallCounter>;
139
140 RefCallCounter obj1, obj2;
141
142 RefCallPtr ptr1 = fbl::AdoptRef<RefCallCounter>(&obj1);
143 RefCallPtr ptr2 = fbl::AdoptRef<RefCallCounter>(&obj2);
144 RefCallPtr also_ptr1 = ptr1;
145 RefCallPtr null_ref_ptr;
146
147 EXPECT_TRUE(ptr1 == ptr1);
148 EXPECT_FALSE(ptr1 != ptr1);
149
150 EXPECT_FALSE(ptr1 == ptr2);
151 EXPECT_TRUE(ptr1 != ptr2);
152
153 EXPECT_TRUE(ptr1 == also_ptr1);
154 EXPECT_FALSE(ptr1 != also_ptr1);
155
156 EXPECT_TRUE(ptr1 != null_ref_ptr);
157 EXPECT_TRUE(ptr1 != nullptr);
158 EXPECT_TRUE(nullptr != ptr1);
159 EXPECT_FALSE(ptr1 == null_ref_ptr);
160 EXPECT_FALSE(ptr1 == nullptr);
161 EXPECT_FALSE(nullptr == ptr1);
162
163 EXPECT_TRUE(null_ref_ptr == nullptr);
164 EXPECT_FALSE(null_ref_ptr != nullptr);
165 EXPECT_TRUE(nullptr == null_ref_ptr);
166 EXPECT_FALSE(nullptr != null_ref_ptr);
167
168 END_TEST;
169 }
170
171 namespace upcasting {
172
173 class Stats {
174 public:
Stats()175 Stats() { }
~Stats()176 ~Stats() { destroy_count_++; }
177
Reset()178 static void Reset() {
179 adopt_calls_ = 0;
180 add_ref_calls_ = 0;
181 release_calls_ = 0;
182 destroy_count_ = 0;
183 }
184
Adopt()185 void Adopt() { adopt_calls_++; }
186
AddRef()187 void AddRef() {
188 ref_count_++;
189 add_ref_calls_++;
190 }
191
Release()192 bool Release() {
193 ref_count_--;
194 release_calls_++;
195 return (ref_count_ <= 0);
196 }
197
adopt_calls()198 static uint32_t adopt_calls() { return adopt_calls_; }
add_ref_calls()199 static uint32_t add_ref_calls() { return add_ref_calls_; }
release_calls()200 static uint32_t release_calls() { return release_calls_; }
destroy_count()201 static uint32_t destroy_count() { return destroy_count_; }
202
203 private:
204 int ref_count_ = 1;
205 static uint32_t adopt_calls_;
206 static uint32_t add_ref_calls_;
207 static uint32_t release_calls_;
208 static uint32_t destroy_count_;
209 };
210
211 uint32_t Stats::adopt_calls_ = 0;
212 uint32_t Stats::add_ref_calls_ = 0;
213 uint32_t Stats::release_calls_ = 0;
214 uint32_t Stats::destroy_count_ = 0;
215
216 class A : public Stats {
217 public:
~A()218 virtual ~A() { stuff = 0u; }
219
220 private:
221 volatile uint32_t stuff;
222 };
223
224 class B {
225 public:
~B()226 ~B() { stuff = 1u; }
227
228 private:
229 volatile uint32_t stuff;
230 };
231
232 class C : public A, public B {
233 public:
~C()234 ~C() { }
235 };
236
237 class D : public A {
238 public:
~D()239 virtual ~D() { stuff = 2u; }
240
241 private:
242 volatile uint32_t stuff;
243 };
244
245 template <typename T>
246 struct custom_delete {
operator ()__anoned50383b0111::upcasting::custom_delete247 inline void operator()(T* ptr) const {
248 enum { type_must_be_complete = sizeof(T) };
249 delete ptr;
250 }
251 };
252
253 template <typename RefPtrType>
handoff_lvalue_fn(const RefPtrType & ptr)254 static bool handoff_lvalue_fn(const RefPtrType& ptr) {
255 BEGIN_TEST;
256 EXPECT_NONNULL(ptr);
257 END_TEST;
258 }
259
260 template <typename RefPtrType>
handoff_copy_fn(RefPtrType ptr)261 static bool handoff_copy_fn(RefPtrType ptr) {
262 BEGIN_TEST;
263 EXPECT_NONNULL(ptr);
264 END_TEST;
265 }
266
267 template <typename RefPtrType>
handoff_rvalue_fn(RefPtrType && ptr)268 static bool handoff_rvalue_fn(RefPtrType&& ptr) {
269 BEGIN_TEST;
270 EXPECT_NONNULL(ptr);
271 END_TEST;
272 }
273
274 class OverloadTestHelper {
275 public:
276 enum class Result {
277 None,
278 ClassA,
279 ClassB,
280 ClassD,
281 };
282
PassByCopy(fbl::RefPtr<A>)283 void PassByCopy(fbl::RefPtr<A>) { result_ = Result::ClassA; }
PassByCopy(fbl::RefPtr<D>)284 void PassByCopy(fbl::RefPtr<D>) { result_ = Result::ClassD; }
285
286 #if TEST_WILL_NOT_COMPILE || 0
287 // Enabling this overload should cause the overload test to fail to compile
288 // due to ambiguity (it does not know whether to cast fbl::RefPtr<C> to fbl::RefPtr<A>
289 // or fbl::RefPtr<B>)
PassByCopy(fbl::RefPtr<B>)290 void PassByCopy(fbl::RefPtr<B>) { result_ = Result::ClassB; }
291 #endif
292
PassByMove(fbl::RefPtr<A> &&)293 void PassByMove(fbl::RefPtr<A>&&) { result_ = Result::ClassA; }
PassByMove(fbl::RefPtr<D> &&)294 void PassByMove(fbl::RefPtr<D>&&) { result_ = Result::ClassD; }
295
296 #if TEST_WILL_NOT_COMPILE || 0
297 // Enabling this overload should cause the overload test to fail to compile
298 // due to ambiguity (it does not know whether to cast fbl::RefPtr<C> to fbl::RefPtr<A>
299 // or fbl::RefPtr<B>)
PassByMove(fbl::RefPtr<B> &&)300 void PassByMove(fbl::RefPtr<B>&&) { result_ = Result::ClassB; }
301 #endif
302
result() const303 Result result() const { return result_; }
304
305 private:
306 Result result_ = Result::None;
307 };
308
309 template <typename Base,
310 typename Derived>
do_test()311 static bool do_test() {
312 BEGIN_TEST;
313 fbl::AllocChecker ac;
314
315 fbl::RefPtr<Derived> derived_ptr;
316
317 // Construct RefPtr<Base> with a copy and implicit cast
318 Stats::Reset();
319 derived_ptr = fbl::AdoptRef<Derived>(new (&ac) Derived());
320 ASSERT_TRUE(ac.check());
321 {
322 EXPECT_NONNULL(derived_ptr);
323 EXPECT_EQ(1, Stats::adopt_calls());
324 EXPECT_EQ(0, Stats::add_ref_calls());
325 EXPECT_EQ(0, Stats::release_calls());
326 EXPECT_EQ(0, Stats::destroy_count());
327
328 fbl::RefPtr<Base> base_ptr(derived_ptr);
329
330 EXPECT_NONNULL(derived_ptr);
331 EXPECT_NONNULL(base_ptr);
332 EXPECT_EQ(1, Stats::adopt_calls());
333 EXPECT_EQ(1, Stats::add_ref_calls());
334 EXPECT_EQ(0, Stats::release_calls());
335 EXPECT_EQ(0, Stats::destroy_count());
336 }
337
338 // Construct RefPtr<Base> with a move and implicit cast
339 {
340 EXPECT_NONNULL(derived_ptr);
341 EXPECT_EQ(1, Stats::adopt_calls());
342 EXPECT_EQ(1, Stats::add_ref_calls());
343 EXPECT_EQ(1, Stats::release_calls());
344 EXPECT_EQ(0, Stats::destroy_count());
345
346 fbl::RefPtr<Base> base_ptr(std::move(derived_ptr));
347
348 EXPECT_NULL(derived_ptr);
349 EXPECT_NONNULL(base_ptr);
350 EXPECT_EQ(1, Stats::adopt_calls());
351 EXPECT_EQ(1, Stats::add_ref_calls());
352 EXPECT_EQ(1, Stats::release_calls());
353 EXPECT_EQ(0, Stats::destroy_count());
354 }
355
356 EXPECT_EQ(1, Stats::adopt_calls());
357 EXPECT_EQ(1, Stats::add_ref_calls());
358 EXPECT_EQ(2, Stats::release_calls());
359 EXPECT_EQ(1, Stats::destroy_count());
360
361 // Assign RefPtr<Base> at declaration time with a copy
362 Stats::Reset();
363 derived_ptr = fbl::AdoptRef<Derived>(new (&ac) Derived());
364 ASSERT_TRUE(ac.check());
365 {
366 EXPECT_NONNULL(derived_ptr);
367 EXPECT_EQ(1, Stats::adopt_calls());
368 EXPECT_EQ(0, Stats::add_ref_calls());
369 EXPECT_EQ(0, Stats::release_calls());
370 EXPECT_EQ(0, Stats::destroy_count());
371
372 fbl::RefPtr<Base> base_ptr = derived_ptr;
373
374 EXPECT_NONNULL(derived_ptr);
375 EXPECT_NONNULL(base_ptr);
376 EXPECT_EQ(1, Stats::adopt_calls());
377 EXPECT_EQ(1, Stats::add_ref_calls());
378 EXPECT_EQ(0, Stats::release_calls());
379 EXPECT_EQ(0, Stats::destroy_count());
380 }
381
382 // Assign RefPtr<Base> at declaration time with a std::move
383 {
384 EXPECT_NONNULL(derived_ptr);
385 EXPECT_EQ(1, Stats::adopt_calls());
386 EXPECT_EQ(1, Stats::add_ref_calls());
387 EXPECT_EQ(1, Stats::release_calls());
388 EXPECT_EQ(0, Stats::destroy_count());
389
390 fbl::RefPtr<Base> base_ptr = std::move(derived_ptr);
391
392 EXPECT_NULL(derived_ptr);
393 EXPECT_NONNULL(base_ptr);
394 EXPECT_EQ(1, Stats::adopt_calls());
395 EXPECT_EQ(1, Stats::add_ref_calls());
396 EXPECT_EQ(1, Stats::release_calls());
397 EXPECT_EQ(0, Stats::destroy_count());
398 }
399
400 EXPECT_EQ(1, Stats::adopt_calls());
401 EXPECT_EQ(1, Stats::add_ref_calls());
402 EXPECT_EQ(2, Stats::release_calls());
403 EXPECT_EQ(1, Stats::destroy_count());
404
405 // Assign RefPtr<Base> after declaration with a copy
406 Stats::Reset();
407 derived_ptr = fbl::AdoptRef<Derived>(new (&ac) Derived());
408 ASSERT_TRUE(ac.check());
409 {
410 EXPECT_NONNULL(derived_ptr);
411 EXPECT_EQ(1, Stats::adopt_calls());
412 EXPECT_EQ(0, Stats::add_ref_calls());
413 EXPECT_EQ(0, Stats::release_calls());
414 EXPECT_EQ(0, Stats::destroy_count());
415
416 fbl::RefPtr<Base> base_ptr;
417 base_ptr = derived_ptr;
418
419 EXPECT_NONNULL(derived_ptr);
420 EXPECT_NONNULL(base_ptr);
421 EXPECT_EQ(1, Stats::adopt_calls());
422 EXPECT_EQ(1, Stats::add_ref_calls());
423 EXPECT_EQ(0, Stats::release_calls());
424 EXPECT_EQ(0, Stats::destroy_count());
425 }
426
427 // Assign RefPtr<Base> after declaration with a std::move
428 {
429 EXPECT_NONNULL(derived_ptr);
430 EXPECT_EQ(1, Stats::adopt_calls());
431 EXPECT_EQ(1, Stats::add_ref_calls());
432 EXPECT_EQ(1, Stats::release_calls());
433 EXPECT_EQ(0, Stats::destroy_count());
434
435 fbl::RefPtr<Base> base_ptr;
436 base_ptr = std::move(derived_ptr);
437
438 EXPECT_NULL(derived_ptr);
439 EXPECT_NONNULL(base_ptr);
440 EXPECT_EQ(1, Stats::adopt_calls());
441 EXPECT_EQ(1, Stats::add_ref_calls());
442 EXPECT_EQ(1, Stats::release_calls());
443 EXPECT_EQ(0, Stats::destroy_count());
444 }
445
446 EXPECT_EQ(1, Stats::adopt_calls());
447 EXPECT_EQ(1, Stats::add_ref_calls());
448 EXPECT_EQ(2, Stats::release_calls());
449 EXPECT_EQ(1, Stats::destroy_count());
450
451 // Pass the pointer to a function as an lvalue reference with an implicit cast
452 Stats::Reset();
453 derived_ptr = fbl::AdoptRef<Derived>(new (&ac) Derived());
454 ASSERT_TRUE(ac.check());
455 {
456 EXPECT_NONNULL(derived_ptr);
457 EXPECT_EQ(1, Stats::adopt_calls());
458 EXPECT_EQ(0, Stats::add_ref_calls());
459 EXPECT_EQ(0, Stats::release_calls());
460 EXPECT_EQ(0, Stats::destroy_count());
461
462 // Note: counter to intuition, we actually do expect this to bump the
463 // reference count regardless of what the target function does with the
464 // reference-to-pointer passed to it. We are not passing a const
465 // reference to a RefPtr<Derived>; instead we are creating a temp
466 // RefPtr<Base> (which is where the addref happens) and then passing a
467 // refernce to *that* to the function.
468 bool test_res = handoff_lvalue_fn<fbl::RefPtr<Base>>(derived_ptr);
469 EXPECT_TRUE(test_res);
470
471 EXPECT_NONNULL(derived_ptr);
472 EXPECT_EQ(1, Stats::adopt_calls());
473 EXPECT_EQ(1, Stats::add_ref_calls());
474 EXPECT_EQ(1, Stats::release_calls());
475 EXPECT_EQ(0, Stats::destroy_count());
476 }
477
478 // Pass the pointer to a function with a copy and implicit cast
479 {
480 bool test_res = handoff_copy_fn<fbl::RefPtr<Base>>(derived_ptr);
481 EXPECT_TRUE(test_res);
482
483 EXPECT_NONNULL(derived_ptr);
484 EXPECT_EQ(1, Stats::adopt_calls());
485 EXPECT_EQ(2, Stats::add_ref_calls());
486 EXPECT_EQ(2, Stats::release_calls());
487 EXPECT_EQ(0, Stats::destroy_count());
488 }
489
490 // Pass the pointer to a function as an rvalue reference and implicit cast
491 {
492 bool test_res = handoff_rvalue_fn<fbl::RefPtr<Base>>(std::move(derived_ptr));
493 EXPECT_TRUE(test_res);
494
495 EXPECT_NULL(derived_ptr);
496 EXPECT_EQ(1, Stats::adopt_calls());
497 EXPECT_EQ(2, Stats::add_ref_calls());
498 EXPECT_EQ(3, Stats::release_calls());
499 EXPECT_EQ(1, Stats::destroy_count());
500 }
501
502 END_TEST;
503 }
504
ref_ptr_upcast_test()505 static bool ref_ptr_upcast_test() {
506 BEGIN_TEST;
507 bool test_res;
508
509 // This should work. C derives from A, A has a virtual destructor, and
510 // everything is using the default deleter.
511 test_res = do_test<A, C>();
512 EXPECT_TRUE(test_res);
513
514 #if TEST_WILL_NOT_COMPILE || 0
515 // This should not work. C derives from B, but B has no virtual destructor.
516 test_res = do_test<B, C>();
517 EXPECT_FALSE(test_res);
518 #endif
519
520 #if TEST_WILL_NOT_COMPILE || 0
521 // This should not work. D has a virtual destructor, but it is not a base
522 // class of C.
523 test_res = do_test<D, C>();
524 EXPECT_FALSE(test_res);
525 #endif
526
527 // Test overload resolution. Make a C and the try to pass it to
528 // OverloadTestHelper's various overloaded methods. The compiler should
529 // know which version to pick, and it should pick the RefPtr<A> version, not
530 // the RefPtr<D> version. If the TEST_WILL_NOT_COMPILE check is enabled in
531 // OverloadTestHelper, a RefPtr<B> version will be enabled as well. This
532 // should cause the build to break because of ambiguity.
533 fbl::AllocChecker ac;
534 fbl::RefPtr<C> ptr = fbl::AdoptRef(new (&ac) C());
535 ASSERT_TRUE(ac.check());
536
537 {
538 // Test pass by copy first (so we can reuse our object)
539 OverloadTestHelper helper;
540 helper.PassByCopy(ptr);
541
542 ASSERT_NONNULL(ptr);
543 EXPECT_EQ(OverloadTestHelper::Result::ClassA, helper.result());
544
545 }
546
547 {
548 // Now test pass by move.
549 OverloadTestHelper helper;
550 helper.PassByMove(std::move(ptr));
551
552 EXPECT_NULL(ptr);
553 EXPECT_EQ(OverloadTestHelper::Result::ClassA, helper.result());
554 }
555
556 END_TEST;
557 }
558
559 } // namespace upcasting
560
ref_ptr_adopt_null_test()561 static bool ref_ptr_adopt_null_test() {
562 BEGIN_TEST;
563
564 class C : public fbl::RefCounted<C> {
565 };
566
567 fbl::RefPtr<C> ptr = fbl::AdoptRef(static_cast<C*>(nullptr));
568 EXPECT_NULL(ptr);
569 END_TEST;
570 }
571
ref_ptr_to_const_test()572 static bool ref_ptr_to_const_test() {
573 BEGIN_TEST;
574
575 class C : public fbl::RefCounted<C> {
576 public:
577 explicit C(int x) : x_(x) {}
578
579 int get_x() const { return x_; }
580
581 private:
582 int x_;
583 };
584
585 fbl::AllocChecker ac;
586 fbl::RefPtr<C> refptr = fbl::AdoptRef<C>(new (&ac) C(23));
587 ASSERT_TRUE(ac.check());
588
589 // Copy a ref-ptr to a ref-ptr-to-const.
590 fbl::RefPtr<const C> const_refptr = refptr;
591 // refptr should have been copied, not moved.
592 ASSERT_NONNULL(refptr.get());
593
594 // Call a const member function on a ref-ptr-to-const.
595 EXPECT_NONNULL(const_refptr.get());
596 EXPECT_EQ(const_refptr->get_x(), 23);
597
598 // Move a ref-ptr to a ref-ptr-to-const.
599 fbl::RefPtr<const C> moved_const_refptr = std::move(refptr);
600 ASSERT_NONNULL(moved_const_refptr.get());
601 // Now refptr should have been nulled out.
602 ASSERT_NULL(refptr.get());
603
604 // Move a ref-ptr-to-const into another ref-ptr-to-const.
605 const_refptr.reset();
606 ASSERT_NULL(const_refptr);
607 const_refptr = std::move(moved_const_refptr);
608 ASSERT_NONNULL(const_refptr);
609 ASSERT_NULL(moved_const_refptr);
610
611 END_TEST;
612 }
613
ref_ptr_move_assign()614 static bool ref_ptr_move_assign() {
615 BEGIN_TEST;
616 using RefCallPtr = fbl::RefPtr<RefCallCounter>;
617
618 RefCallCounter counter1, counter2;
619 RefCallPtr ptr1 = fbl::AdoptRef<RefCallCounter>(&counter1);
620 RefCallPtr ptr2 = fbl::AdoptRef<RefCallCounter>(&counter2);
621
622 EXPECT_NE(ptr1.get(), ptr2.get());
623 EXPECT_NONNULL(ptr1);
624 EXPECT_NONNULL(ptr2);
625
626 ptr1 = std::move(ptr2);
627 EXPECT_EQ(ptr1.get(), &counter2);
628 EXPECT_NULL(ptr2);
629
630 EXPECT_EQ(1, counter1.release_calls());
631 EXPECT_EQ(0, counter2.release_calls());
632
633 // Test self-assignment
634 #ifdef __clang__
635 #pragma clang diagnostic push
636 #pragma clang diagnostic ignored "-Wself-move"
637 #endif
638 ptr1 = std::move(ptr1);
639 #ifdef __clang__
640 #pragma clang diagnostic pop
641 #endif
642 EXPECT_EQ(ptr1.get(), &counter2);
643 EXPECT_EQ(0, counter2.release_calls());
644
645 END_TEST;
646 }
647
648 } // namespace
649
650 BEGIN_TEST_CASE(ref_ptr_tests)
651 RUN_NAMED_TEST("Ref Pointer", ref_ptr_test)
652 RUN_NAMED_TEST("Ref Pointer Comparison", ref_ptr_compare_test)
653 RUN_NAMED_TEST("Ref Pointer Upcast", upcasting::ref_ptr_upcast_test)
654 RUN_NAMED_TEST("Ref Pointer Adopt null", ref_ptr_adopt_null_test)
655 RUN_NAMED_TEST("Ref Pointer To Const", ref_ptr_to_const_test)
656 RUN_NAMED_TEST("Ref Pointer Move Assignment", ref_ptr_move_assign)
657 END_TEST_CASE(ref_ptr_tests);
658