Fix copyright lines
[folly.git] / folly / test / ReplaceableTest.cpp
1 /*
2  * Copyright 2017-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 Basic {};
26 struct alignas(128) BigAlign {};
27 struct HasConst final {
28   bool const b1;
29   HasConst() noexcept : b1(true) {}
30   explicit HasConst(bool b) noexcept : b1(b) {}
31   HasConst(HasConst const& b) noexcept : b1(b.b1) {}
32   HasConst(HasConst&& b) noexcept : b1(b.b1) {}
33   HasConst& operator=(HasConst const&) = delete;
34   HasConst& operator=(HasConst&&) = delete;
35 };
36 struct HasRef final {
37   int& i1;
38   explicit HasRef(int& i) noexcept(false) : i1(i) {}
39   HasRef(HasRef const& i) noexcept(false) : i1(i.i1) {}
40   HasRef(HasRef&& i) noexcept(false) : i1(i.i1) {}
41   HasRef& operator=(HasRef const&) = delete;
42   HasRef& operator=(HasRef&&) = delete;
43   ~HasRef() noexcept(false) {
44     ++i1;
45   }
46 };
47
48 struct OddA;
49 struct OddB {
50   OddB() = delete;
51   OddB(std::initializer_list<int>, int) noexcept(false) {}
52   explicit OddB(OddA&&) {}
53   explicit OddB(OddA const&) noexcept(false) {}
54   OddB(OddB&&) = delete;
55   OddB(OddB const&) = delete;
56   OddB& operator=(OddB&&) = delete;
57   OddB& operator=(OddB const&) = delete;
58   ~OddB() = default;
59 };
60 struct OddA {
61   OddA() = delete;
62   explicit OddA(OddB&&) noexcept {}
63   explicit OddA(OddB const&) = delete;
64   OddA(OddA&&) = delete;
65   OddA(OddA const&) = delete;
66   OddA& operator=(OddA&&) = delete;
67   OddA& operator=(OddA const&) = delete;
68   ~OddA() noexcept(false) {}
69 };
70 struct Indestructible {
71   ~Indestructible() = delete;
72 };
73 } // namespace
74
75 template <typename T>
76 struct ReplaceableStaticAttributeTest : Test {};
77 using StaticAttributeTypes = ::testing::Types<
78     char,
79     short,
80     int,
81     long,
82     float,
83     double,
84     char[11],
85     Basic,
86     BigAlign,
87     HasConst,
88     HasRef,
89     OddA,
90     OddB,
91     Indestructible>;
92 TYPED_TEST_CASE(ReplaceableStaticAttributeTest, StaticAttributeTypes);
93
94 template <typename T>
95 struct ReplaceableStaticAttributePairTest : Test {};
96 using StaticAttributePairTypes = ::testing::
97     Types<std::pair<int, long>, std::pair<OddA, OddB>, std::pair<OddB, OddA>>;
98 TYPED_TEST_CASE(ReplaceableStaticAttributePairTest, StaticAttributePairTypes);
99
100 TYPED_TEST(ReplaceableStaticAttributeTest, size) {
101   EXPECT_EQ(sizeof(TypeParam), sizeof(Replaceable<TypeParam>));
102 }
103 TYPED_TEST(ReplaceableStaticAttributeTest, align) {
104   EXPECT_EQ(alignof(TypeParam), alignof(Replaceable<TypeParam>));
105 }
106 TYPED_TEST(ReplaceableStaticAttributeTest, destructible) {
107   EXPECT_EQ(
108       std::is_destructible<TypeParam>::value,
109       std::is_destructible<Replaceable<TypeParam>>::value);
110 }
111 TYPED_TEST(ReplaceableStaticAttributeTest, trivially_destructible) {
112   EXPECT_EQ(
113       std::is_trivially_destructible<TypeParam>::value,
114       std::is_trivially_destructible<Replaceable<TypeParam>>::value);
115 }
116 TYPED_TEST(ReplaceableStaticAttributeTest, default_constructible) {
117   EXPECT_EQ(
118       std::is_default_constructible<TypeParam>::value,
119       std::is_default_constructible<Replaceable<TypeParam>>::value);
120 }
121 TYPED_TEST(ReplaceableStaticAttributeTest, move_constructible) {
122   EXPECT_EQ(
123       std::is_move_constructible<TypeParam>::value,
124       std::is_move_constructible<Replaceable<TypeParam>>::value);
125 }
126 TYPED_TEST(ReplaceableStaticAttributeTest, copy_constructible) {
127   EXPECT_EQ(
128       std::is_copy_constructible<TypeParam>::value,
129       std::is_copy_constructible<Replaceable<TypeParam>>::value);
130 }
131 TYPED_TEST(ReplaceableStaticAttributeTest, move_assignable) {
132   EXPECT_EQ(
133       std::is_move_constructible<TypeParam>::value,
134       std::is_move_assignable<Replaceable<TypeParam>>::value);
135 }
136 TYPED_TEST(ReplaceableStaticAttributeTest, copy_assignable) {
137   EXPECT_EQ(
138       std::is_copy_constructible<TypeParam>::value,
139       std::is_copy_assignable<Replaceable<TypeParam>>::value);
140 }
141 TYPED_TEST(ReplaceableStaticAttributeTest, nothrow_destructible) {
142   EXPECT_EQ(
143       std::is_nothrow_destructible<TypeParam>::value,
144       std::is_nothrow_destructible<Replaceable<TypeParam>>::value);
145 }
146 TYPED_TEST(ReplaceableStaticAttributeTest, nothrow_default_constructible) {
147   EXPECT_EQ(
148       std::is_nothrow_default_constructible<TypeParam>::value,
149       std::is_nothrow_default_constructible<Replaceable<TypeParam>>::value);
150 }
151 TYPED_TEST(ReplaceableStaticAttributeTest, nothrow_move_constructible) {
152   EXPECT_EQ(
153       std::is_nothrow_move_constructible<TypeParam>::value,
154       std::is_nothrow_move_constructible<Replaceable<TypeParam>>::value);
155 }
156 TYPED_TEST(ReplaceableStaticAttributeTest, nothrow_copy_constructible) {
157   EXPECT_EQ(
158       std::is_nothrow_copy_constructible<TypeParam>::value,
159       std::is_nothrow_copy_constructible<Replaceable<TypeParam>>::value);
160 }
161 TYPED_TEST(ReplaceableStaticAttributeTest, nothrow_move_assignable) {
162   EXPECT_EQ(
163       std::is_nothrow_destructible<TypeParam>::value &&
164           std::is_nothrow_copy_constructible<TypeParam>::value,
165       std::is_nothrow_move_assignable<Replaceable<TypeParam>>::value);
166 }
167 TYPED_TEST(ReplaceableStaticAttributeTest, nothrow_copy_assignable) {
168   EXPECT_EQ(
169       std::is_nothrow_destructible<TypeParam>::value &&
170           std::is_nothrow_copy_constructible<TypeParam>::value,
171       std::is_nothrow_copy_assignable<Replaceable<TypeParam>>::value);
172 }
173 TYPED_TEST(ReplaceableStaticAttributeTest, replaceable) {
174   EXPECT_FALSE(is_replaceable<TypeParam>::value);
175   EXPECT_TRUE(is_replaceable<Replaceable<TypeParam>>::value);
176 }
177
178 TYPED_TEST(ReplaceableStaticAttributePairTest, copy_construct) {
179   using T = typename TypeParam::first_type;
180   using U = typename TypeParam::second_type;
181   EXPECT_EQ(
182       (std::is_constructible<T, U const&>::value),
183       (std::is_constructible<Replaceable<T>, Replaceable<U> const&>::value));
184 }
185 TYPED_TEST(ReplaceableStaticAttributePairTest, move_construct) {
186   using T = typename TypeParam::first_type;
187   using U = typename TypeParam::second_type;
188   EXPECT_EQ(
189       (std::is_constructible<T, U&&>::value),
190       (std::is_constructible<Replaceable<T>, Replaceable<U>&&>::value));
191 }
192 TYPED_TEST(ReplaceableStaticAttributePairTest, copy_assign) {
193   using T = typename TypeParam::first_type;
194   using U = typename TypeParam::second_type;
195   EXPECT_EQ(
196       (std::is_convertible<U, T>::value && std::is_destructible<T>::value &&
197        std::is_copy_constructible<T>::value),
198       (std::is_assignable<Replaceable<T>, Replaceable<U> const&>::value));
199 }
200 TYPED_TEST(ReplaceableStaticAttributePairTest, move_assign) {
201   using T = typename TypeParam::first_type;
202   using U = typename TypeParam::second_type;
203   EXPECT_EQ(
204       (std::is_convertible<U, T>::value && std::is_destructible<T>::value &&
205        std::is_move_constructible<T>::value),
206       (std::is_assignable<Replaceable<T>, Replaceable<U>&&>::value));
207 }
208 TYPED_TEST(ReplaceableStaticAttributePairTest, nothrow_copy_construct) {
209   using T = typename TypeParam::first_type;
210   using U = typename TypeParam::second_type;
211   EXPECT_EQ(
212       (std::is_nothrow_constructible<T, U const&>::value &&
213        std::is_nothrow_destructible<T>::value),
214       (std::is_nothrow_constructible<Replaceable<T>, Replaceable<U> const&>::
215            value));
216 }
217 TYPED_TEST(ReplaceableStaticAttributePairTest, nothrow_move_construct) {
218   using T = typename TypeParam::first_type;
219   using U = typename TypeParam::second_type;
220   EXPECT_EQ(
221       (std::is_nothrow_constructible<T, U&&>::value &&
222        std::is_nothrow_destructible<T>::value),
223       (std::is_nothrow_constructible<Replaceable<T>, Replaceable<U>&&>::value));
224 }
225 TYPED_TEST(ReplaceableStaticAttributePairTest, nothrow_copy_assign) {
226   using T = typename TypeParam::first_type;
227   using U = typename TypeParam::second_type;
228   EXPECT_EQ(
229       (std::is_nothrow_constructible<T, U const&>::value &&
230        std::is_nothrow_destructible<T>::value),
231       (std::is_nothrow_assignable<Replaceable<T>, Replaceable<U> const&>::
232            value));
233 }
234 TYPED_TEST(ReplaceableStaticAttributePairTest, nothrow_move_assign) {
235   using T = typename TypeParam::first_type;
236   using U = typename TypeParam::second_type;
237   EXPECT_EQ(
238       (std::is_nothrow_constructible<T, U&&>::value &&
239        std::is_nothrow_destructible<T>::value),
240       (std::is_nothrow_assignable<Replaceable<T>, Replaceable<U>&&>::value));
241 }
242
243 TEST(ReplaceableTest, Basics) {
244   auto rHasConstA = make_replaceable<HasConst>();
245   auto rHasConstB = make_replaceable<HasConst>(false);
246   EXPECT_TRUE(rHasConstA->b1);
247   EXPECT_FALSE(rHasConstB->b1);
248   rHasConstA = rHasConstB;
249   EXPECT_FALSE(rHasConstA->b1);
250   EXPECT_FALSE(rHasConstB->b1);
251   rHasConstB.emplace(true);
252   EXPECT_FALSE(rHasConstA->b1);
253   EXPECT_TRUE(rHasConstB->b1);
254   rHasConstA = std::move(rHasConstB);
255   EXPECT_TRUE(rHasConstA->b1);
256   EXPECT_TRUE(rHasConstB->b1);
257 }
258
259 TEST(ReplaceableTest, Constructors) {
260   Basic b{};
261   // From existing `T`
262   auto rBasicCopy1 = Replaceable<Basic>(b);
263   auto rBasicMove1 = Replaceable<Basic>(std::move(b));
264   // From existing `Replaceable<T>`
265   auto rBasicCopy2 = Replaceable<Basic>(rBasicCopy1);
266   auto rBasicMove2 = Replaceable<Basic>(std::move(rBasicMove1));
267   (void)rBasicCopy2;
268   (void)rBasicMove2;
269 }
270
271 TEST(ReplaceableTest, DestructsWhenExpected) {
272   int i{0};
273   {
274     Replaceable<HasRef> rHasRefA{i};
275     Replaceable<HasRef> rHasRefB{i};
276     EXPECT_EQ(0, i);
277     rHasRefA = rHasRefB;
278     EXPECT_EQ(1, i);
279     rHasRefB.emplace(i);
280     EXPECT_EQ(2, i);
281     rHasRefA = std::move(rHasRefB);
282     EXPECT_EQ(3, i);
283   }
284   EXPECT_EQ(5, i);
285 }
286
287 TEST(ReplaceableTest, Conversions) {
288   Replaceable<OddB> rOddB{in_place, {1, 2, 3}, 4};
289   Replaceable<OddA> rOddA{std::move(rOddB)};
290   Replaceable<OddB> rOddB2{rOddA};
291 }