a34f982f19bbcb8fad4d562281c87343535c1338
[folly.git] / folly / futures / test / WhileDoTest.cpp
1 /*
2  * Copyright 2015 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 <memory>
18 #include <mutex>
19 #include <queue>
20
21 #include <gtest/gtest.h>
22 #include <glog/logging.h>
23
24 #include <folly/futures/Future.h>
25 #include <folly/futures/Promise.h>
26
27 using namespace folly;
28
29 inline void popAndFulfillPromise(
30     std::queue<std::shared_ptr<Promise<Unit>>>& ps,
31     std::mutex& ps_mutex) {
32   ps_mutex.lock();
33   auto p = ps.front();
34   ps.pop();
35   ps_mutex.unlock();
36   p->setValue();
37 }
38
39 inline std::function<Future<Unit>(void)> makeThunk(
40     std::queue<std::shared_ptr<Promise<Unit>>>& ps,
41     int& interrupt,
42     std::mutex& ps_mutex) {
43   return [&]() mutable {
44     auto p = std::make_shared<Promise<Unit>>();
45     p->setInterruptHandler([&](exception_wrapper const& e) {
46       ++interrupt;
47     });
48     ps_mutex.lock();
49     ps.push(p);
50     ps_mutex.unlock();
51
52     return p->getFuture();
53   };
54 }
55
56 inline std::function<bool(void)> makePred(int& i) {
57   return [&]() {
58     bool res = i < 3;
59     ++i;
60     return res;
61   };
62 }
63
64 TEST(WhileDo, success) {
65   std::queue<std::shared_ptr<Promise<Unit>>> ps;
66   std::mutex ps_mutex;
67   int i = 0;
68   int interrupt = 0;
69   bool complete = false;
70   bool failure = false;
71
72   auto pred = makePred(i);
73   auto thunk = makeThunk(ps, interrupt, ps_mutex);
74   auto f = folly::whileDo(pred, thunk)
75     .then([&]() mutable { complete = true; })
76     .onError([&] (FutureException& e) { failure = true; });
77
78   popAndFulfillPromise(ps, ps_mutex);
79   EXPECT_FALSE(complete);
80   EXPECT_FALSE(failure);
81
82   popAndFulfillPromise(ps, ps_mutex);
83   EXPECT_FALSE(complete);
84   EXPECT_FALSE(failure);
85
86   popAndFulfillPromise(ps, ps_mutex);
87   EXPECT_TRUE(f.isReady());
88   EXPECT_TRUE(complete);
89   EXPECT_FALSE(failure);
90 }
91
92 TEST(WhileDo, failure) {
93   std::queue<std::shared_ptr<Promise<Unit>>> ps;
94   std::mutex ps_mutex;
95   int i = 0;
96   int interrupt = 0;
97   bool complete = false;
98   bool failure = false;
99
100   auto pred = makePred(i);
101   auto thunk = makeThunk(ps, interrupt, ps_mutex);
102   auto f = folly::whileDo(pred, thunk)
103     .then([&]() mutable { complete = true; })
104     .onError([&] (FutureException& e) { failure = true; });
105
106   popAndFulfillPromise(ps, ps_mutex);
107   EXPECT_FALSE(complete);
108   EXPECT_FALSE(failure);
109
110   ps_mutex.lock();
111   auto p2 = ps.front();
112   ps.pop();
113   ps_mutex.unlock();
114   FutureException eggs("eggs");
115   p2->setException(eggs);
116
117   EXPECT_TRUE(f.isReady());
118   EXPECT_FALSE(complete);
119   EXPECT_TRUE(failure);
120 }
121
122 TEST(WhileDo, interrupt) {
123   std::queue<std::shared_ptr<Promise<Unit>>> ps;
124   std::mutex ps_mutex;
125   int i = 0;
126   int interrupt = 0;
127   bool complete = false;
128   bool failure = false;
129
130   auto pred = makePred(i);
131   auto thunk = makeThunk(ps, interrupt, ps_mutex);
132   auto f = folly::whileDo(pred, thunk)
133     .then([&]() mutable { complete = true; })
134     .onError([&] (FutureException& e) { failure = true; });
135
136   EXPECT_EQ(0, interrupt);
137
138   FutureException eggs("eggs");
139   f.raise(eggs);
140
141   for (int i = 1; i <= 3; ++i) {
142     EXPECT_EQ(1, interrupt);
143     popAndFulfillPromise(ps, ps_mutex);
144   }
145 }