1// Copyright 2017 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_ptr.h>
7#include <fbl/ref_counted.h>
8#include <fbl/unique_ptr.h>
9#include <fbl/type_support.h>
10#include <unittest/unittest.h>
11
12namespace {
13
14template <typename T> struct PtrTraits;
15
16template <typename T>
17struct PtrTraits<fbl::unique_ptr<T>> {
18    using ObjType = typename fbl::remove_cv<T>::type;
19    static fbl::unique_ptr<T> MakePointer(T* raw) { return fbl::unique_ptr<T>(raw); }
20};
21
22template <typename T>
23struct PtrTraits<fbl::RefPtr<T>> {
24    using ObjType = typename fbl::remove_cv<T>::type;
25    static fbl::RefPtr<T> MakePointer(T* raw) { return fbl::AdoptRef<T>(raw); }
26};
27
28
29class TestBase {
30public:
31    TestBase() { recycle_was_called_ = false; }
32    static bool recycle_was_called() { return recycle_was_called_; }
33protected:
34    static bool recycle_was_called_;
35};
36
37bool TestBase::recycle_was_called_;
38
39class TestPublicRecycle : public TestBase,
40                          public fbl::Recyclable<TestPublicRecycle> {
41public:
42    void fbl_recycle() {
43        recycle_was_called_ = true;
44        delete this;
45    }
46};
47
48class RefedTestPublicRecycle : public TestBase,
49                               public fbl::RefCounted<RefedTestPublicRecycle>,
50                               public fbl::Recyclable<RefedTestPublicRecycle> {
51public:
52    void fbl_recycle() {
53        recycle_was_called_ = true;
54        delete this;
55    }
56};
57
58class TestPrivateRecycle : public TestBase,
59                           public fbl::Recyclable<TestPrivateRecycle> {
60private:
61    friend class fbl::Recyclable<TestPrivateRecycle>;
62    void fbl_recycle() {
63        recycle_was_called_ = true;
64        delete this;
65    }
66};
67
68class RefedTestPrivateRecycle : public TestBase,
69                                public fbl::RefCounted<RefedTestPrivateRecycle>,
70                                public fbl::Recyclable<RefedTestPrivateRecycle> {
71private:
72    friend class fbl::Recyclable<RefedTestPrivateRecycle>;
73    void fbl_recycle() {
74        recycle_was_called_ = true;
75        delete this;
76    }
77};
78
79struct FailNoMethod : public fbl::Recyclable<FailNoMethod> { };
80struct FailBadRet : public fbl::Recyclable<FailBadRet> { int fbl_recycle() { return 1; } };
81struct FailBadArg : public fbl::Recyclable<FailBadArg> { void fbl_recycle(int a = 1) {} };
82class  FailNotVis : public fbl::Recyclable<FailNotVis> { void fbl_recycle() {} };
83
84#if TEST_WILL_NOT_COMPILE || 0
85struct FailCVBase1 : public fbl::Recyclable<const FailCVBase1> { void fbl_recycle() {} };
86#endif
87#if TEST_WILL_NOT_COMPILE || 0
88struct FailCVBase2 : public fbl::Recyclable<volatile FailCVBase2> { void fbl_recycle() {} };
89#endif
90#if TEST_WILL_NOT_COMPILE || 0
91struct FailCVBase3 : public fbl::Recyclable<const volatile FailCVBase3> { void fbl_recycle() {} };
92#endif
93
94template <typename T>
95static bool do_test() {
96    BEGIN_TEST;
97
98    fbl::AllocChecker ac;
99    auto ptr = PtrTraits<T>::MakePointer(new (&ac) typename PtrTraits<T>::ObjType);
100
101    ASSERT_TRUE(ac.check());
102    EXPECT_FALSE(TestBase::recycle_was_called());
103
104    ptr = nullptr;
105    EXPECT_TRUE(TestBase::recycle_was_called());
106
107    END_TEST;
108}
109
110}  // anon namespace
111
112BEGIN_TEST_CASE(fbl_recycle)
113RUN_NAMED_TEST("public unique_ptr fbl_recycle()",
114               do_test<fbl::unique_ptr<TestPublicRecycle>>)
115RUN_NAMED_TEST("public const unique_ptr fbl_recycle()",
116               do_test<fbl::unique_ptr<const TestPublicRecycle>>)
117RUN_NAMED_TEST("public volatile unique_ptr fbl_recycle()",
118               do_test<fbl::unique_ptr<volatile TestPublicRecycle>>)
119RUN_NAMED_TEST("public const volatile unique_ptr fbl_recycle()",
120               do_test<fbl::unique_ptr<const volatile TestPublicRecycle>>)
121RUN_NAMED_TEST("private unique_ptr fbl_recycle()",
122               do_test<fbl::unique_ptr<TestPrivateRecycle>>)
123RUN_NAMED_TEST("private const unique_ptr fbl_recycle()",
124               do_test<fbl::unique_ptr<const TestPrivateRecycle>>)
125RUN_NAMED_TEST("private volatile unique_ptr fbl_recycle()",
126               do_test<fbl::unique_ptr<volatile TestPrivateRecycle>>)
127RUN_NAMED_TEST("private const volatile unique_ptr fbl_recycle()",
128               do_test<fbl::unique_ptr<const volatile TestPrivateRecycle>>)
129RUN_NAMED_TEST("public RefPtr fbl_recycle()",
130               do_test<fbl::RefPtr<RefedTestPublicRecycle>>)
131RUN_NAMED_TEST("private RefPtr fbl_recycle()",
132               do_test<fbl::RefPtr<RefedTestPrivateRecycle>>)
133#if TEST_WILL_NOT_COMPILE || 0
134// TODO(johngro) : If we ever support RefPtr<>s to const/volatile objects,
135// instantiate tests for them here.
136RUN_NAMED_TEST("public const RefPtr fbl_recycle()",
137               do_test<fbl::RefPtr<const RefedTestPublicRecycle>>)
138RUN_NAMED_TEST("public volatile RefPtr fbl_recycle()",
139               do_test<fbl::RefPtr<volatile RefedTestPublicRecycle>>)
140RUN_NAMED_TEST("public const volatile RefPtr fbl_recycle()",
141               do_test<fbl::RefPtr<const volatile RefedTestPublicRecycle>>)
142RUN_NAMED_TEST("private const RefPtr fbl_recycle()",
143               do_test<fbl::RefPtr<const RefedTestPrivateRecycle>>)
144RUN_NAMED_TEST("private volatile RefPtr fbl_recycle()",
145               do_test<fbl::RefPtr<volatile RefedTestPrivateRecycle>>)
146RUN_NAMED_TEST("private const volatile RefPtr fbl_recycle()",
147               do_test<fbl::RefPtr<const volatile RefedTestPrivateRecycle>>)
148#endif
149#if TEST_WILL_NOT_COMPILE || 0
150RUN_NAMED_TEST("FailNoMethod", do_test<fbl::unique_ptr<FailNoMethod>>);
151#endif
152#if TEST_WILL_NOT_COMPILE || 0
153RUN_NAMED_TEST("FailBadRet",   do_test<fbl::unique_ptr<FailBadRet>>);
154#endif
155#if TEST_WILL_NOT_COMPILE || 0
156RUN_NAMED_TEST("FailBadArg",   do_test<fbl::unique_ptr<FailBadArg>>);
157#endif
158#if TEST_WILL_NOT_COMPILE || 0
159RUN_NAMED_TEST("FailNotVis",   do_test<fbl::unique_ptr<FailBadArg>>);
160#endif
161END_TEST_CASE(fbl_recycle);
162