Replaceable
[folly.git] / folly / test / ReplaceableTest.cpp
1 /*
2  * Copyright 2004-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <folly/Replaceable.h>
18
19 #include <folly/portability/GTest.h>
20
21 using namespace ::testing;
22 using namespace ::folly;
23
24 namespace {
25 struct alignas(128) BigAlign {};
26 struct HasConst final {
27   bool const b1;
28   HasConst() noexcept : b1(true) {}
29   explicit HasConst(bool b) noexcept : b1(b) {}
30   HasConst(HasConst const& b) noexcept : b1(b.b1) {}
31   HasConst(HasConst&& b) noexcept : b1(b.b1) {}
32   HasConst& operator=(HasConst const&) = delete;
33   HasConst& operator=(HasConst&&) = delete;
34 };
35 struct HasRef final {
36   int& i1;
37   explicit HasRef(int& i) noexcept(false) : i1(i) {}
38   HasRef(HasRef const& i) noexcept(false) : i1(i.i1) {}
39   HasRef(HasRef&& i) noexcept(false) : i1(i.i1) {}
40   HasRef& operator=(HasRef const&) = delete;
41   HasRef& operator=(HasRef&&) = delete;
42   ~HasRef() noexcept(false) {
43     ++i1;
44   }
45 };
46
47 struct OddA;
48 struct OddB {
49   OddB() = delete;
50   OddB(std::initializer_list<int>, int) noexcept(false) {}
51   explicit OddB(OddA&&) {}
52   explicit OddB(OddA const&) noexcept(false) {}
53   OddB(OddB&&) = delete;
54   OddB(OddB const&) = delete;
55   OddB& operator=(OddB&&) = delete;
56   OddB& operator=(OddB const&) = delete;
57   ~OddB() = default;
58 };
59 struct OddA {
60   OddA() = delete;
61   explicit OddA(OddB&&) noexcept {}
62   explicit OddA(OddB const&) = delete;
63   OddA(OddA&&) = delete;
64   OddA(OddA const&) = delete;
65   OddA& operator=(OddA&&) = delete;
66   OddA& operator=(OddA const&) = delete;
67   ~OddA() noexcept(false) {}
68 };
69 struct Indestructible {
70   ~Indestructible() = delete;
71 };
72 } // anonymous namespace
73
74 template <typename T>
75 struct ReplaceableStaticAttributeTest : Test {};
76 using StaticAttributeTypes = ::testing::Types<
77     char,
78     short,
79     int,
80     long,
81     float,
82     double,
83     char[11],
84     BigAlign,
85     HasConst,
86     HasRef,
87     OddA,
88     OddB,
89     Indestructible>;
90 TYPED_TEST_CASE(ReplaceableStaticAttributeTest, StaticAttributeTypes);
91
92 template <typename T>
93 struct ReplaceableStaticAttributePairTest : Test {};
94 using StaticAttributePairTypes = ::testing::
95     Types<std::pair<int, long>, std::pair<OddA, OddB>, std::pair<OddB, OddA>>;
96 TYPED_TEST_CASE(ReplaceableStaticAttributePairTest, StaticAttributePairTypes);
97
98 TYPED_TEST(ReplaceableStaticAttributeTest, size) {
99   EXPECT_EQ(sizeof(TypeParam), sizeof(Replaceable<TypeParam>));
100 }
101 TYPED_TEST(ReplaceableStaticAttributeTest, align) {
102   EXPECT_EQ(alignof(TypeParam), alignof(Replaceable<TypeParam>));
103 }
104 TYPED_TEST(ReplaceableStaticAttributeTest, destructible) {
105   EXPECT_EQ(
106       std::is_destructible<TypeParam>::value,
107       std::is_destructible<Replaceable<TypeParam>>::value);
108 }
109 TYPED_TEST(ReplaceableStaticAttributeTest, trivially_destructible) {
110   EXPECT_EQ(
111       std::is_trivially_destructible<TypeParam>::value,
112       std::is_trivially_destructible<Replaceable<TypeParam>>::value);
113 }
114 TYPED_TEST(ReplaceableStaticAttributeTest, default_constructible) {
115   EXPECT_EQ(
116       std::is_default_constructible<TypeParam>::value,
117       std::is_default_constructible<Replaceable<TypeParam>>::value);
118 }
119 TYPED_TEST(ReplaceableStaticAttributeTest, move_constructible) {
120   EXPECT_EQ(
121       std::is_move_constructible<TypeParam>::value,
122       std::is_move_constructible<Replaceable<TypeParam>>::value);
123 }
124 TYPED_TEST(ReplaceableStaticAttributeTest, copy_constructible) {
125   EXPECT_EQ(
126       std::is_copy_constructible<TypeParam>::value,
127       std::is_copy_constructible<Replaceable<TypeParam>>::value);
128 }
129 TYPED_TEST(ReplaceableStaticAttributeTest, move_assignable) {
130   EXPECT_EQ(
131       std::is_move_constructible<TypeParam>::value,
132       std::is_move_assignable<Replaceable<TypeParam>>::value);
133 }
134 TYPED_TEST(ReplaceableStaticAttributeTest, copy_assignable) {
135   EXPECT_EQ(
136       std::is_copy_constructible<TypeParam>::value,
137       std::is_copy_assignable<Replaceable<TypeParam>>::value);
138 }
139 TYPED_TEST(ReplaceableStaticAttributeTest, nothrow_destructible) {
140   EXPECT_EQ(
141       std::is_nothrow_destructible<TypeParam>::value,
142       std::is_nothrow_destructible<Replaceable<TypeParam>>::value);
143 }
144 TYPED_TEST(ReplaceableStaticAttributeTest, nothrow_default_constructible) {
145   EXPECT_EQ(
146       std::is_nothrow_default_constructible<TypeParam>::value,
147       std::is_nothrow_default_constructible<Replaceable<TypeParam>>::value);
148 }
149 TYPED_TEST(ReplaceableStaticAttributeTest, nothrow_move_constructible) {
150   EXPECT_EQ(
151       std::is_nothrow_move_constructible<TypeParam>::value,
152       std::is_nothrow_move_constructible<Replaceable<TypeParam>>::value);
153 }
154 TYPED_TEST(ReplaceableStaticAttributeTest, nothrow_copy_constructible) {
155   EXPECT_EQ(
156       std::is_nothrow_copy_constructible<TypeParam>::value,
157       std::is_nothrow_copy_constructible<Replaceable<TypeParam>>::value);
158 }
159 TYPED_TEST(ReplaceableStaticAttributeTest, nothrow_move_assignable) {
160   EXPECT_EQ(
161       std::is_nothrow_destructible<TypeParam>::value &&
162           std::is_nothrow_copy_constructible<TypeParam>::value,
163       std::is_nothrow_move_assignable<Replaceable<TypeParam>>::value);
164 }
165 TYPED_TEST(ReplaceableStaticAttributeTest, nothrow_copy_assignable) {
166   EXPECT_EQ(
167       std::is_nothrow_destructible<TypeParam>::value &&
168           std::is_nothrow_copy_constructible<TypeParam>::value,
169       std::is_nothrow_copy_assignable<Replaceable<TypeParam>>::value);
170 }
171
172 TYPED_TEST(ReplaceableStaticAttributePairTest, copy_construct) {
173   using T = typename TypeParam::first_type;
174   using U = typename TypeParam::second_type;
175   EXPECT_EQ(
176       (std::is_constructible<T, U const&>::value),
177       (std::is_constructible<Replaceable<T>, Replaceable<U> const&>::value));
178 }
179 TYPED_TEST(ReplaceableStaticAttributePairTest, move_construct) {
180   using T = typename TypeParam::first_type;
181   using U = typename TypeParam::second_type;
182   EXPECT_EQ(
183       (std::is_constructible<T, U&&>::value),
184       (std::is_constructible<Replaceable<T>, Replaceable<U>&&>::value));
185 }
186 TYPED_TEST(ReplaceableStaticAttributePairTest, copy_assign) {
187   using T = typename TypeParam::first_type;
188   using U = typename TypeParam::second_type;
189   EXPECT_EQ(
190       (std::is_convertible<U, T>::value && std::is_destructible<T>::value &&
191        std::is_copy_constructible<T>::value),
192       (std::is_assignable<Replaceable<T>, Replaceable<U> const&>::value));
193 }
194 TYPED_TEST(ReplaceableStaticAttributePairTest, move_assign) {
195   using T = typename TypeParam::first_type;
196   using U = typename TypeParam::second_type;
197   EXPECT_EQ(
198       (std::is_convertible<U, T>::value && std::is_destructible<T>::value &&
199        std::is_move_constructible<T>::value),
200       (std::is_assignable<Replaceable<T>, Replaceable<U>&&>::value));
201 }
202 TYPED_TEST(ReplaceableStaticAttributePairTest, nothrow_copy_construct) {
203   using T = typename TypeParam::first_type;
204   using U = typename TypeParam::second_type;
205   EXPECT_EQ(
206       (std::is_nothrow_constructible<T, U const&>::value &&
207        std::is_nothrow_destructible<T>::value),
208       (std::is_nothrow_constructible<Replaceable<T>, Replaceable<U> const&>::
209            value));
210 }
211 TYPED_TEST(ReplaceableStaticAttributePairTest, nothrow_move_construct) {
212   using T = typename TypeParam::first_type;
213   using U = typename TypeParam::second_type;
214   EXPECT_EQ(
215       (std::is_nothrow_constructible<T, U&&>::value &&
216        std::is_nothrow_destructible<T>::value),
217       (std::is_nothrow_constructible<Replaceable<T>, Replaceable<U>&&>::value));
218 }
219 TYPED_TEST(ReplaceableStaticAttributePairTest, nothrow_copy_assign) {
220   using T = typename TypeParam::first_type;
221   using U = typename TypeParam::second_type;
222   EXPECT_EQ(
223       (std::is_nothrow_constructible<T, U const&>::value &&
224        std::is_nothrow_destructible<T>::value),
225       (std::is_nothrow_assignable<Replaceable<T>, Replaceable<U> const&>::
226            value));
227 }
228 TYPED_TEST(ReplaceableStaticAttributePairTest, nothrow_move_assign) {
229   using T = typename TypeParam::first_type;
230   using U = typename TypeParam::second_type;
231   EXPECT_EQ(
232       (std::is_nothrow_constructible<T, U&&>::value &&
233        std::is_nothrow_destructible<T>::value),
234       (std::is_nothrow_assignable<Replaceable<T>, Replaceable<U>&&>::value));
235 }
236
237 TEST(ReplaceableTest, Basics) {
238   auto rHasConstA = make_replaceable<HasConst>();
239   auto rHasConstB = make_replaceable<HasConst>(false);
240   EXPECT_TRUE(rHasConstA->b1);
241   EXPECT_FALSE(rHasConstB->b1);
242   rHasConstA = rHasConstB;
243   EXPECT_FALSE(rHasConstA->b1);
244   EXPECT_FALSE(rHasConstB->b1);
245   rHasConstB.emplace(true);
246   EXPECT_FALSE(rHasConstA->b1);
247   EXPECT_TRUE(rHasConstB->b1);
248   rHasConstA = std::move(rHasConstB);
249   EXPECT_TRUE(rHasConstA->b1);
250   EXPECT_TRUE(rHasConstB->b1);
251 }
252
253 TEST(ReplaceableTest, DestructsWhenExpected) {
254   int i{0};
255   {
256     Replaceable<HasRef> rHasRefA{i};
257     Replaceable<HasRef> rHasRefB{i};
258     EXPECT_EQ(0, i);
259     rHasRefA = rHasRefB;
260     EXPECT_EQ(1, i);
261     rHasRefB.emplace(i);
262     EXPECT_EQ(2, i);
263     rHasRefA = std::move(rHasRefB);
264     EXPECT_EQ(3, i);
265   }
266   EXPECT_EQ(5, i);
267 }
268
269 TEST(ReplaceableTest, Conversions) {
270   Replaceable<OddB> rOddB{in_place, {1, 2, 3}, 4};
271   Replaceable<OddA> rOddA{std::move(rOddB)};
272   Replaceable<OddB> rOddB2{rOddA};
273 }