]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | /* | |
4 | * Ceph - scalable distributed file system | |
5 | * | |
6 | * Copyright (C) 2017 Red Hat, Inc. | |
7 | * | |
8 | * This is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU Lesser General Public | |
10 | * License version 2.1, as published by the Free Software | |
11 | * Foundation. See file COPYING. | |
12 | * | |
13 | */ | |
14 | ||
1e59de90 | 15 | #include <compare> |
11fdf7f2 | 16 | #include <gtest/gtest.h> |
1e59de90 | 17 | #include "common/static_ptr.h" |
11fdf7f2 TL |
18 | |
19 | using ceph::static_ptr; | |
20 | using ceph::make_static; | |
21 | ||
22 | class base { | |
23 | public: | |
24 | virtual int func() = 0; | |
25 | virtual ~base() = default; | |
26 | }; | |
27 | ||
28 | class sibling1 : public base { | |
29 | public: | |
30 | int func() override { return 0; } | |
31 | }; | |
32 | ||
33 | class sibling2 : public base { | |
34 | public: | |
35 | int func() override { return 9; } | |
36 | virtual int call(int) = 0; | |
37 | }; | |
38 | ||
39 | class grandchild : public sibling2 { | |
40 | protected: | |
41 | int val; | |
42 | public: | |
43 | explicit grandchild(int val) : val(val) {} | |
44 | virtual int call(int n) override { return n * val; } | |
45 | }; | |
46 | ||
47 | class great_grandchild : public grandchild { | |
48 | public: | |
49 | explicit great_grandchild(int val) : grandchild(val) {} | |
50 | int call(int n) override { return n + val; } | |
51 | }; | |
52 | ||
1e59de90 | 53 | #ifdef __cpp_lib_three_way_comparison |
11fdf7f2 TL |
54 | TEST(StaticPtr, EmptyCreation) { |
55 | static_ptr<base, sizeof(grandchild)> p; | |
56 | EXPECT_FALSE(p); | |
57 | EXPECT_EQ(p, nullptr); | |
58 | EXPECT_EQ(nullptr, p); | |
59 | EXPECT_TRUE(p.get() == nullptr); | |
60 | } | |
61 | ||
62 | TEST(StaticPtr, CreationCall) { | |
63 | { | |
64 | static_ptr<base, sizeof(grandchild)> p(std::in_place_type_t<sibling1>{}); | |
65 | EXPECT_TRUE(p); | |
66 | EXPECT_FALSE(p == nullptr); | |
67 | EXPECT_FALSE(nullptr == p); | |
68 | EXPECT_FALSE(p.get() == nullptr); | |
69 | EXPECT_EQ(p->func(), 0); | |
70 | EXPECT_EQ((*p).func(), 0); | |
71 | EXPECT_EQ((p.get())->func(), 0); | |
72 | } | |
73 | { | |
74 | auto p = make_static<base, sibling1>(); | |
75 | EXPECT_TRUE(p); | |
76 | EXPECT_FALSE(p == nullptr); | |
77 | EXPECT_FALSE(nullptr == p); | |
78 | EXPECT_FALSE(p.get() == nullptr); | |
79 | EXPECT_EQ(p->func(), 0); | |
80 | EXPECT_EQ((*p).func(), 0); | |
81 | EXPECT_EQ((p.get())->func(), 0); | |
82 | } | |
83 | } | |
84 | ||
85 | TEST(StaticPtr, CreateReset) { | |
86 | { | |
87 | static_ptr<base, sizeof(grandchild)> p(std::in_place_type_t<sibling1>{}); | |
88 | EXPECT_EQ((p.get())->func(), 0); | |
89 | p.reset(); | |
90 | EXPECT_FALSE(p); | |
91 | EXPECT_EQ(p, nullptr); | |
92 | EXPECT_EQ(nullptr, p); | |
93 | EXPECT_TRUE(p.get() == nullptr); | |
94 | } | |
95 | { | |
96 | static_ptr<base, sizeof(grandchild)> p(std::in_place_type_t<sibling1>{}); | |
97 | EXPECT_EQ((p.get())->func(), 0); | |
98 | p = nullptr; | |
99 | EXPECT_FALSE(p); | |
100 | EXPECT_EQ(p, nullptr); | |
101 | EXPECT_EQ(nullptr, p); | |
102 | EXPECT_TRUE(p.get() == nullptr); | |
103 | } | |
104 | } | |
1e59de90 | 105 | #endif // __cpp_lib_three_way_comparison |
11fdf7f2 TL |
106 | |
107 | TEST(StaticPtr, CreateEmplace) { | |
108 | static_ptr<base, sizeof(grandchild)> p(std::in_place_type_t<sibling1>{}); | |
109 | EXPECT_EQ((p.get())->func(), 0); | |
110 | p.emplace<grandchild>(30); | |
111 | EXPECT_EQ(p->func(), 9); | |
112 | } | |
113 | ||
f67539c2 | 114 | TEST(StaticPtr, Move) { |
11fdf7f2 TL |
115 | // Won't compile. Good. |
116 | // static_ptr<base, sizeof(base)> p1(std::in_place_type_t<grandchild>{}, 3); | |
117 | ||
118 | static_ptr<base, sizeof(base)> p1(std::in_place_type_t<sibling1>{}); | |
119 | static_ptr<base, sizeof(grandchild)> p2(std::in_place_type_t<grandchild>{}, | |
120 | 3); | |
121 | ||
11fdf7f2 TL |
122 | p2 = std::move(p1); |
123 | EXPECT_EQ(p1->func(), 0); | |
124 | } | |
125 | ||
126 | TEST(StaticPtr, ImplicitUpcast) { | |
127 | static_ptr<base, sizeof(grandchild)> p1; | |
128 | static_ptr<sibling2, sizeof(grandchild)> p2(std::in_place_type_t<grandchild>{}, 3); | |
129 | ||
11fdf7f2 TL |
130 | p1 = std::move(p2); |
131 | EXPECT_EQ(p1->func(), 9); | |
132 | ||
133 | p2.reset(); | |
134 | ||
135 | // Doesn't compile. Good. | |
136 | // p2 = p1; | |
137 | } | |
138 | ||
139 | TEST(StaticPtr, StaticCast) { | |
140 | static_ptr<base, sizeof(grandchild)> p1(std::in_place_type_t<grandchild>{}, 3); | |
141 | static_ptr<sibling2, sizeof(grandchild)> p2; | |
142 | ||
11fdf7f2 TL |
143 | p2 = ceph::static_pointer_cast<sibling2, sizeof(grandchild)>(std::move(p1)); |
144 | EXPECT_EQ(p2->func(), 9); | |
145 | EXPECT_EQ(p2->call(10), 30); | |
146 | } | |
147 | ||
148 | TEST(StaticPtr, DynamicCast) { | |
149 | static constexpr auto sz = sizeof(great_grandchild); | |
11fdf7f2 TL |
150 | { |
151 | static_ptr<base, sz> p1(std::in_place_type_t<grandchild>{}, 3); | |
152 | auto p2 = ceph::dynamic_pointer_cast<great_grandchild, sz>(std::move(p1)); | |
153 | EXPECT_FALSE(p2); | |
154 | } | |
155 | ||
11fdf7f2 TL |
156 | { |
157 | static_ptr<base, sz> p1(std::in_place_type_t<grandchild>{}, 3); | |
158 | auto p2 = ceph::dynamic_pointer_cast<grandchild, sz>(std::move(p1)); | |
159 | EXPECT_TRUE(p2); | |
160 | EXPECT_EQ(p2->func(), 9); | |
161 | EXPECT_EQ(p2->call(10), 30); | |
162 | } | |
163 | } | |
164 | ||
165 | class constable { | |
166 | public: | |
167 | int foo() { | |
168 | return 2; | |
169 | } | |
170 | int foo() const { | |
171 | return 5; | |
172 | } | |
173 | }; | |
174 | ||
175 | TEST(StaticPtr, ConstCast) { | |
176 | static constexpr auto sz = sizeof(constable); | |
11fdf7f2 TL |
177 | { |
178 | auto p1 = make_static<const constable>(); | |
179 | EXPECT_EQ(p1->foo(), 5); | |
180 | auto p2 = ceph::const_pointer_cast<constable, sz>(std::move(p1)); | |
181 | static_assert(!std::is_const<decltype(p2)::element_type>{}, | |
182 | "Things are more const than they ought to be."); | |
183 | EXPECT_TRUE(p2); | |
184 | EXPECT_EQ(p2->foo(), 2); | |
185 | } | |
186 | } | |
187 | ||
188 | TEST(StaticPtr, ReinterpretCast) { | |
189 | static constexpr auto sz = sizeof(grandchild); | |
11fdf7f2 TL |
190 | { |
191 | auto p1 = make_static<grandchild>(3); | |
192 | auto p2 = ceph::reinterpret_pointer_cast<constable, sz>(std::move(p1)); | |
193 | static_assert(std::is_same<decltype(p2)::element_type, constable>{}, | |
194 | "Reinterpret is screwy."); | |
195 | auto p3 = ceph::reinterpret_pointer_cast<grandchild, sz>(std::move(p2)); | |
196 | static_assert(std::is_same<decltype(p3)::element_type, grandchild>{}, | |
197 | "Reinterpret is screwy."); | |
198 | EXPECT_EQ(p3->func(), 9); | |
199 | EXPECT_EQ(p3->call(10), 30); | |
200 | } | |
201 | } | |
202 | ||
203 | struct exceptional { | |
204 | exceptional() = default; | |
205 | exceptional(const exceptional& e) { | |
206 | throw std::exception(); | |
207 | } | |
208 | exceptional(exceptional&& e) { | |
209 | throw std::exception(); | |
210 | } | |
211 | }; | |
212 | ||
213 | TEST(StaticPtr, Exceptional) { | |
214 | static_ptr<exceptional> p1(std::in_place_type_t<exceptional>{}); | |
11fdf7f2 TL |
215 | EXPECT_ANY_THROW(static_ptr<exceptional> p2(std::move(p1))); |
216 | } |