Fix copyright lines
[folly.git] / folly / test / IndestructibleTest.cpp
1 /*
2  * Copyright 2016-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/Indestructible.h>
18
19 #include <functional>
20 #include <map>
21 #include <memory>
22 #include <string>
23 #include <tuple>
24
25 #include <folly/Memory.h>
26 #include <folly/portability/GTest.h>
27
28 using namespace std;
29 using namespace folly;
30
31 namespace {
32
33 struct Magic {
34   function<void()> dtor_;
35   function<void()> move_;
36   Magic(function<void()> ctor, function<void()> dtor, function<void()> move)
37       : dtor_(std::move(dtor)), move_(std::move(move)) {
38     ctor();
39   }
40   Magic(Magic&& other) /* may throw */ { *this = std::move(other); }
41   Magic& operator=(Magic&& other) {
42     dtor_ = std::move(other.dtor_);
43     move_ = std::move(other.move_);
44     move_();
45     return *this;
46   }
47   ~Magic() { dtor_(); }
48 };
49
50 class IndestructibleTest : public testing::Test {};
51 } // namespace
52
53 TEST_F(IndestructibleTest, access) {
54   static const Indestructible<map<string, int>> data{
55       map<string, int>{{"key1", 17}, {"key2", 19}, {"key3", 23}}};
56
57   auto& m = *data;
58   EXPECT_EQ(19, m.at("key2"));
59 }
60
61 TEST_F(IndestructibleTest, no_destruction) {
62   int state = 0;
63   int value = 0;
64
65   static Indestructible<Magic> sing(
66       [&] {
67         ++state;
68         value = 7;
69       },
70       [&] { state = -1; },
71       [] {});
72   EXPECT_EQ(1, state);
73   EXPECT_EQ(7, value);
74
75   sing.~Indestructible();
76   EXPECT_EQ(1, state);
77 }
78
79 TEST_F(IndestructibleTest, empty) {
80   static const Indestructible<map<string, int>> data;
81   auto& m = *data;
82   EXPECT_EQ(0, m.size());
83 }
84
85 TEST_F(IndestructibleTest, move) {
86   int state = 0;
87   int value = 0;
88   int moves = 0;
89
90   static Indestructible<Magic> sing( // move assignment
91       [&] {
92         ++state;
93         value = 7;
94       },
95       [&] { state = -1; },
96       [&] { ++moves; });
97
98   EXPECT_EQ(1, state);
99   EXPECT_EQ(7, value);
100   EXPECT_EQ(0, moves);
101
102   // move constructor
103   static Indestructible<Magic> move_ctor(std::move(sing));
104   EXPECT_EQ(1, state);
105   EXPECT_EQ(1, moves);
106
107   // move assignment
108   static Indestructible<Magic> move_assign = std::move(move_ctor);
109   EXPECT_EQ(1, state);
110   EXPECT_EQ(2, moves);
111 }
112
113 TEST_F(IndestructibleTest, disabled_default_ctor) {
114   EXPECT_TRUE((std::is_constructible<Indestructible<int>>::value)) << "sanity";
115
116   struct Foo {
117     Foo(int) {}
118   };
119   EXPECT_FALSE((std::is_constructible<Indestructible<Foo>>::value));
120   EXPECT_FALSE((std::is_constructible<Indestructible<Foo>, Magic>::value));
121   EXPECT_TRUE((std::is_constructible<Indestructible<Foo>, int>::value));
122 }
123
124 TEST_F(IndestructibleTest, list_initialization) {
125   auto map = folly::Indestructible<std::map<int, int>>{{{1, 2}}};
126   EXPECT_EQ(map->at(1), 2);
127 }
128
129 namespace {
130 class InitializerListConstructible {
131  public:
132   InitializerListConstructible(InitializerListConstructible&&) = default;
133   explicit InitializerListConstructible(std::initializer_list<int>) {}
134   InitializerListConstructible(std::initializer_list<double>, double) {}
135 };
136 } // namespace
137
138 TEST_F(IndestructibleTest, initializer_list_in_place_initialization) {
139   using I = InitializerListConstructible;
140   std::ignore = Indestructible<I>{{1, 2, 3, 4}};
141   std::ignore = Indestructible<I>{{1.2}, 4.2};
142 }
143
144 namespace {
145 class ExplicitlyMoveConstructible {
146  public:
147   ExplicitlyMoveConstructible() = default;
148   explicit ExplicitlyMoveConstructible(ExplicitlyMoveConstructible&&) = default;
149 };
150 } // namespace
151
152 TEST_F(IndestructibleTest, list_initialization_explicit_implicit) {
153   using E = ExplicitlyMoveConstructible;
154   using I = std::map<int, int>;
155   EXPECT_TRUE((!std::is_convertible<E, Indestructible<E>>::value));
156   EXPECT_TRUE((std::is_convertible<I, Indestructible<I>>::value));
157 }