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