Fix copyright lines
[folly.git] / folly / futures / test / ThenTest.cpp
1 /*
2  * Copyright 2015-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/futures/Future.h>
18 #include <folly/portability/GTest.h>
19
20 #include <thread>
21
22 using namespace folly;
23
24 namespace {
25 struct Widget {
26   int v_, copied_, moved_;
27   /* implicit */ Widget(int v) : v_(v), copied_(0), moved_(0) {}
28   Widget(const Widget& other)
29     : v_(other.v_), copied_(other.copied_ + 1), moved_(other.moved_) {}
30   Widget(Widget&& other) noexcept
31     : v_(other.v_), copied_(other.copied_), moved_(other.moved_ + 1) {}
32   Widget& operator=(const Widget& /* other */) {
33     throw std::logic_error("unexpected copy assignment");
34   }
35   Widget& operator=(Widget&& /* other */) {
36     throw std::logic_error("unexpected move assignment");
37   }
38 };
39
40 struct CountedWidget : Widget {
41   static std::vector<Widget*> instances_;
42   bool alive = true;
43   /* implicit */ CountedWidget(int v) : Widget(v) {
44     instances_.push_back(this);
45   }
46   CountedWidget(const CountedWidget& other) : Widget(other) {
47     instances_.push_back(this);
48   }
49   CountedWidget(CountedWidget&& other) noexcept(false)
50       : Widget(std::move(other)) {
51     other.alive = false;
52     other.remove();
53     instances_.push_back(this);
54   }
55   ~CountedWidget() {
56     if (alive) {
57       remove();
58     }
59   }
60
61  private:
62   CountedWidget& operator=(const CountedWidget&) = delete;
63   CountedWidget& operator=(CountedWidget&&) = delete;
64
65   void remove() {
66     auto iter = std::find(instances_.begin(), instances_.end(), this);
67     EXPECT_TRUE(iter != instances_.end());
68     instances_.erase(iter);
69   }
70 };
71
72 std::vector<Widget*> CountedWidget::instances_;
73 } // namespace
74
75 TEST(Then, tryConstructor) {
76   auto t = Try<Widget>(23);
77   EXPECT_EQ(t.value().v_, 23);
78   EXPECT_EQ(t.value().copied_, 0);
79   EXPECT_EQ(t.value().moved_, 1);
80 }
81
82 TEST(Then, makeFuture) {
83   auto future = makeFuture<Widget>(23);
84   EXPECT_EQ(future.value().v_, 23);
85   EXPECT_EQ(future.value().copied_, 0);
86   EXPECT_EQ(future.value().moved_, 2);
87 }
88
89 TEST(Then, tryConstRValueReference) {
90   auto future = makeFuture<Widget>(23).then(
91     [](const Try<Widget>&& t) {
92       EXPECT_EQ(t.value().copied_, 0);
93       EXPECT_EQ(t.value().moved_, 2);
94       return t.value().v_;
95     });
96   EXPECT_EQ(future.value(), 23);
97 }
98
99 TEST(Then, tryRValueReference) {
100   auto future = makeFuture<Widget>(23).then(
101     [](Try<Widget>&& t) {
102       EXPECT_EQ(t.value().copied_, 0);
103       EXPECT_EQ(t.value().moved_, 2);
104       return t.value().v_;
105     });
106   EXPECT_EQ(future.value(), 23);
107 }
108
109 TEST(Then, tryLValueReference) {
110   auto future = makeFuture<Widget>(23).then(
111     [](Try<Widget>& t) {
112       EXPECT_EQ(t.value().copied_, 0);
113       EXPECT_EQ(t.value().moved_, 2);
114       return t.value().v_;
115     });
116   EXPECT_EQ(future.value(), 23);
117 }
118
119 TEST(Then, tryConstLValueReference) {
120   auto future = makeFuture<Widget>(23).then(
121     [](const Try<Widget>& t) {
122       EXPECT_EQ(t.value().copied_, 0);
123       EXPECT_EQ(t.value().moved_, 2);
124       return t.value().v_;
125     });
126   EXPECT_EQ(future.value(), 23);
127 }
128
129 TEST(Then, tryValue) {
130   auto future = makeFuture<Widget>(23).then(
131     [](Try<Widget> t) {
132       EXPECT_EQ(t.value().copied_, 0);
133       EXPECT_EQ(t.value().moved_, 3);
134       return t.value().v_;
135     });
136   EXPECT_EQ(future.value(), 23);
137 }
138
139 TEST(Then, tryConstValue) {
140   auto future = makeFuture<Widget>(23).then(
141     [](const Try<Widget> t) {
142       EXPECT_EQ(t.value().copied_, 0);
143       EXPECT_EQ(t.value().moved_, 3);
144       return t.value().v_;
145     });
146   EXPECT_EQ(future.value(), 23);
147 }
148
149 TEST(Then, constRValueReference) {
150   auto future = makeFuture<Widget>(23).then(
151     [](const Widget&& w) {
152       EXPECT_EQ(w.copied_, 0);
153       EXPECT_EQ(w.moved_, 2);
154       return w.v_;
155     });
156   EXPECT_EQ(future.value(), 23);
157 }
158
159 TEST(Then, rValueReference) {
160   auto future = makeFuture<Widget>(23).then(
161     [](Widget&& w) {
162       EXPECT_EQ(w.copied_, 0);
163       EXPECT_EQ(w.moved_, 2);
164       return w.v_;
165     });
166   EXPECT_EQ(future.value(), 23);
167 }
168
169 TEST(Then, lValueReference) {
170   auto future = makeFuture<Widget>(23).then(
171     [](Widget& w) {
172       EXPECT_EQ(w.copied_, 0);
173       EXPECT_EQ(w.moved_, 2);
174       return w.v_;
175     });
176   EXPECT_EQ(future.value(), 23);
177 }
178
179 TEST(Then, constLValueReference) {
180   auto future = makeFuture<Widget>(23).then(
181     [](const Widget& w) {
182       EXPECT_EQ(w.copied_, 0);
183       EXPECT_EQ(w.moved_, 2);
184       return w.v_;
185     });
186   EXPECT_EQ(future.value(), 23);
187 }
188
189 TEST(Then, value) {
190   auto future = makeFuture<Widget>(23).then(
191     [](Widget w) {
192       EXPECT_EQ(w.copied_, 0);
193       EXPECT_EQ(w.moved_, 3);
194       return w.v_;
195     });
196   EXPECT_EQ(future.value(), 23);
197 }
198
199 TEST(Then, constValue) {
200   auto future = makeFuture<Widget>(23).then(
201     [](const Widget w) {
202       EXPECT_EQ(w.copied_, 0);
203       EXPECT_EQ(w.moved_, 3);
204       return w.v_;
205     });
206   EXPECT_EQ(future.value(), 23);
207 }
208
209 TEST(Then, objectAliveDuringImmediateNoParamContinuation) {
210   auto f = makeFuture<CountedWidget>(23);
211   auto called = false;
212   f.then([&] {
213     EXPECT_EQ(CountedWidget::instances_.size(), 1u);
214     EXPECT_EQ(CountedWidget::instances_[0]->v_, 23);
215     called = true;
216   });
217   EXPECT_EQ(true, called);
218 }
219
220 TEST(Then, objectAliveDuringDeferredNoParamContinuation) {
221   auto p = Promise<CountedWidget>{};
222   bool called = false;
223   p.getFuture().then([&] {
224     EXPECT_EQ(CountedWidget::instances_.size(), 1u);
225     EXPECT_EQ(CountedWidget::instances_[0]->v_, 23);
226     called = true;
227   });
228   p.setValue(CountedWidget{23});
229   EXPECT_EQ(true, called);
230 }
231
232 TEST(Then, voidThenShouldPropagateExceptions) {
233   EXPECT_FALSE(makeFuture(42).then().hasException());
234   EXPECT_TRUE(makeFuture<int>(std::runtime_error("err"))
235              .then().hasException());
236 }