blob: 55ca6135eb4eac59feb317425d61ffcd8b87cf1f [file] [log] [blame]
Brian Silvermanda861352019-02-02 16:42:28 -08001#include "catch.hpp"
2#include "optional.hpp"
3#include <string>
4
5#define TOKENPASTE(x, y) x##y
6#define TOKENPASTE2(x, y) TOKENPASTE(x, y)
7#define STATIC_REQUIRE(e) \
8 constexpr bool TOKENPASTE2(rqure, __LINE__) = e; \
9 REQUIRE(e);
10
11constexpr int get_int(int) { return 42; }
12TL_OPTIONAL_11_CONSTEXPR tl::optional<int> get_opt_int(int) { return 42; }
13
14// What is Clang Format up to?!
15TEST_CASE("Monadic operations", "[monadic]") {
16 SECTION("map") { // lhs is empty
17 tl::optional<int> o1;
18 auto o1r = o1.map([](int i) { return i + 2; });
19 STATIC_REQUIRE((std::is_same<decltype(o1r), tl::optional<int>>::value));
20 REQUIRE(!o1r);
21
22 // lhs has value
23 tl::optional<int> o2 = 40;
24 auto o2r = o2.map([](int i) { return i + 2; });
25 STATIC_REQUIRE((std::is_same<decltype(o2r), tl::optional<int>>::value));
26 REQUIRE(o2r.value() == 42);
27
28 struct rval_call_map {
29 double operator()(int) && { return 42.0; };
30 };
31
32 // ensure that function object is forwarded
33 tl::optional<int> o3 = 42;
34 auto o3r = o3.map(rval_call_map{});
35 STATIC_REQUIRE((std::is_same<decltype(o3r), tl::optional<double>>::value));
36 REQUIRE(o3r.value() == 42);
37
38 // ensure that lhs is forwarded
39 tl::optional<int> o4 = 40;
40 auto o4r = std::move(o4).map([](int &&i) { return i + 2; });
41 STATIC_REQUIRE((std::is_same<decltype(o4r), tl::optional<int>>::value));
42 REQUIRE(o4r.value() == 42);
43
44 // ensure that lhs is const-propagated
45 const tl::optional<int> o5 = 40;
46 auto o5r = o5.map([](const int &i) { return i + 2; });
47 STATIC_REQUIRE((std::is_same<decltype(o5r), tl::optional<int>>::value));
48 REQUIRE(o5r.value() == 42);
49
50 // test void return
51 tl::optional<int> o7 = 40;
52 auto f7 = [](const int &i) { return; };
53 auto o7r = o7.map(f7);
54 STATIC_REQUIRE(
55 (std::is_same<decltype(o7r), tl::optional<tl::monostate>>::value));
56 REQUIRE(o7r.has_value());
57
58 // test each overload in turn
59 tl::optional<int> o8 = 42;
60 auto o8r = o8.map([](int) { return 42; });
61 REQUIRE(*o8r == 42);
62
63 tl::optional<int> o9 = 42;
64 auto o9r = o9.map([](int) { return; });
65 REQUIRE(o9r);
66
67 tl::optional<int> o12 = 42;
68 auto o12r = std::move(o12).map([](int) { return 42; });
69 REQUIRE(*o12r == 42);
70
71 tl::optional<int> o13 = 42;
72 auto o13r = std::move(o13).map([](int) { return; });
73 REQUIRE(o13r);
74
75 const tl::optional<int> o16 = 42;
76 auto o16r = o16.map([](int) { return 42; });
77 REQUIRE(*o16r == 42);
78
79 const tl::optional<int> o17 = 42;
80 auto o17r = o17.map([](int) { return; });
81 REQUIRE(o17r);
82
83 const tl::optional<int> o20 = 42;
84 auto o20r = std::move(o20).map([](int) { return 42; });
85 REQUIRE(*o20r == 42);
86
87 const tl::optional<int> o21 = 42;
88 auto o21r = std::move(o21).map([](int) { return; });
89 REQUIRE(o21r);
90
91 tl::optional<int> o24 = tl::nullopt;
92 auto o24r = o24.map([](int) { return 42; });
93 REQUIRE(!o24r);
94
95 tl::optional<int> o25 = tl::nullopt;
96 auto o25r = o25.map([](int) { return; });
97 REQUIRE(!o25r);
98
99 tl::optional<int> o28 = tl::nullopt;
100 auto o28r = std::move(o28).map([](int) { return 42; });
101 REQUIRE(!o28r);
102
103 tl::optional<int> o29 = tl::nullopt;
104 auto o29r = std::move(o29).map([](int) { return; });
105 REQUIRE(!o29r);
106
107 const tl::optional<int> o32 = tl::nullopt;
108 auto o32r = o32.map([](int) { return 42; });
109 REQUIRE(!o32r);
110
111 const tl::optional<int> o33 = tl::nullopt;
112 auto o33r = o33.map([](int) { return; });
113 REQUIRE(!o33r);
114
115 const tl::optional<int> o36 = tl::nullopt;
116 auto o36r = std::move(o36).map([](int) { return 42; });
117 REQUIRE(!o36r);
118
119 const tl::optional<int> o37 = tl::nullopt;
120 auto o37r = std::move(o37).map([](int) { return; });
121 REQUIRE(!o37r);
122
123 // callable which returns a reference
124 tl::optional<int> o38 = 42;
125 auto o38r = o38.map([](int &i) -> const int & { return i; });
126 REQUIRE(o38r);
127 REQUIRE(*o38r == 42);
128
129 int i = 42;
130 tl::optional<int&> o39 = i;
131 o39.map([](int& x){x = 12;});
132 REQUIRE(i == 12);
133 }
134
135 SECTION("map constexpr") {
136#if !defined(_MSC_VER) && defined(TL_OPTIONAL_CXX14)
137 // test each overload in turn
138 constexpr tl::optional<int> o16 = 42;
139 constexpr auto o16r = o16.map(get_int);
140 STATIC_REQUIRE(*o16r == 42);
141
142 constexpr tl::optional<int> o20 = 42;
143 constexpr auto o20r = std::move(o20).map(get_int);
144 STATIC_REQUIRE(*o20r == 42);
145
146 constexpr tl::optional<int> o32 = tl::nullopt;
147 constexpr auto o32r = o32.map(get_int);
148 STATIC_REQUIRE(!o32r);
149 constexpr tl::optional<int> o36 = tl::nullopt;
150 constexpr auto o36r = std::move(o36).map(get_int);
151 STATIC_REQUIRE(!o36r);
152#endif
153 }
154
155 SECTION("and_then") {
156
157 // lhs is empty
158 tl::optional<int> o1;
159 auto o1r = o1.and_then([](int i) { return tl::optional<float>{42}; });
160 STATIC_REQUIRE((std::is_same<decltype(o1r), tl::optional<float>>::value));
161 REQUIRE(!o1r);
162
163 // lhs has value
164 tl::optional<int> o2 = 12;
165 auto o2r = o2.and_then([](int i) { return tl::optional<float>{42}; });
166 STATIC_REQUIRE((std::is_same<decltype(o2r), tl::optional<float>>::value));
167 REQUIRE(o2r.value() == 42.f);
168
169 // lhs is empty, rhs returns empty
170 tl::optional<int> o3;
171 auto o3r = o3.and_then([](int i) { return tl::optional<float>{}; });
172 STATIC_REQUIRE((std::is_same<decltype(o3r), tl::optional<float>>::value));
173 REQUIRE(!o3r);
174
175 // rhs returns empty
176 tl::optional<int> o4 = 12;
177 auto o4r = o4.and_then([](int i) { return tl::optional<float>{}; });
178 STATIC_REQUIRE((std::is_same<decltype(o4r), tl::optional<float>>::value));
179 REQUIRE(!o4r);
180
181 struct rval_call_and_then {
182 tl::optional<double> operator()(int) && {
183 return tl::optional<double>(42.0);
184 };
185 };
186
187 // ensure that function object is forwarded
188 tl::optional<int> o5 = 42;
189 auto o5r = o5.and_then(rval_call_and_then{});
190 STATIC_REQUIRE((std::is_same<decltype(o5r), tl::optional<double>>::value));
191 REQUIRE(o5r.value() == 42);
192
193 // ensure that lhs is forwarded
194 tl::optional<int> o6 = 42;
195 auto o6r =
196 std::move(o6).and_then([](int &&i) { return tl::optional<double>(i); });
197 STATIC_REQUIRE((std::is_same<decltype(o6r), tl::optional<double>>::value));
198 REQUIRE(o6r.value() == 42);
199
200 // ensure that function object is const-propagated
201 const tl::optional<int> o7 = 42;
202 auto o7r =
203 o7.and_then([](const int &i) { return tl::optional<double>(i); });
204 STATIC_REQUIRE((std::is_same<decltype(o7r), tl::optional<double>>::value));
205 REQUIRE(o7r.value() == 42);
206
207 // test each overload in turn
208 tl::optional<int> o8 = 42;
209 auto o8r = o8.and_then([](int i) { return tl::make_optional(42); });
210 REQUIRE(*o8r == 42);
211
212 tl::optional<int> o9 = 42;
213 auto o9r =
214 std::move(o9).and_then([](int i) { return tl::make_optional(42); });
215 REQUIRE(*o9r == 42);
216
217 const tl::optional<int> o10 = 42;
218 auto o10r = o10.and_then([](int i) { return tl::make_optional(42); });
219 REQUIRE(*o10r == 42);
220
221 const tl::optional<int> o11 = 42;
222 auto o11r =
223 std::move(o11).and_then([](int i) { return tl::make_optional(42); });
224 REQUIRE(*o11r == 42);
225
226 tl::optional<int> o16 = tl::nullopt;
227 auto o16r = o16.and_then([](int i) { return tl::make_optional(42); });
228 REQUIRE(!o16r);
229
230 tl::optional<int> o17 = tl::nullopt;
231 auto o17r =
232 std::move(o17).and_then([](int i) { return tl::make_optional(42); });
233 REQUIRE(!o17r);
234
235 const tl::optional<int> o18 = tl::nullopt;
236 auto o18r = o18.and_then([](int i) { return tl::make_optional(42); });
237 REQUIRE(!o18r);
238
239 const tl::optional<int> o19 = tl::nullopt;
240 auto o19r = std::move(o19).and_then([](int i) { return tl::make_optional(42); });
241 REQUIRE(!o19r);
242
243 int i = 3;
244 tl::optional<int&> o20{i};
245 std::move(o20).and_then([](int& r){return tl::optional<int&>{++r};});
246 REQUIRE(o20);
247 REQUIRE(i == 4);
248 }
249
250 SECTION("constexpr and_then") {
251#if !defined(_MSC_VER) && defined(TL_OPTIONAL_CXX14)
252
253 constexpr tl::optional<int> o10 = 42;
254 constexpr auto o10r = o10.and_then(get_opt_int);
255 REQUIRE(*o10r == 42);
256
257 constexpr tl::optional<int> o11 = 42;
258 constexpr auto o11r = std::move(o11).and_then(get_opt_int);
259 REQUIRE(*o11r == 42);
260
261 constexpr tl::optional<int> o18 = tl::nullopt;
262 constexpr auto o18r = o18.and_then(get_opt_int);
263 REQUIRE(!o18r);
264
265 constexpr tl::optional<int> o19 = tl::nullopt;
266 constexpr auto o19r = std::move(o19).and_then(get_opt_int);
267 REQUIRE(!o19r);
268#endif
269 }
270
271 SECTION("or else") {
272 tl::optional<int> o1 = 42;
273 REQUIRE(*(o1.or_else([] { return tl::make_optional(13); })) == 42);
274
275 tl::optional<int> o2;
276 REQUIRE(*(o2.or_else([] { return tl::make_optional(13); })) == 13);
277 }
278
279 SECTION("disjunction") {
280 tl::optional<int> o1 = 42;
281 tl::optional<int> o2 = 12;
282 tl::optional<int> o3;
283
284 REQUIRE(*o1.disjunction(o2) == 42);
285 REQUIRE(*o1.disjunction(o3) == 42);
286 REQUIRE(*o2.disjunction(o1) == 12);
287 REQUIRE(*o2.disjunction(o3) == 12);
288 REQUIRE(*o3.disjunction(o1) == 42);
289 REQUIRE(*o3.disjunction(o2) == 12);
290 }
291
292 SECTION("conjunction") {
293 tl::optional<int> o1 = 42;
294 REQUIRE(*o1.conjunction(42.0) == 42.0);
295 REQUIRE(*o1.conjunction(std::string{"hello"}) == std::string{"hello"});
296
297 tl::optional<int> o2;
298 REQUIRE(!o2.conjunction(42.0));
299 REQUIRE(!o2.conjunction(std::string{"hello"}));
300 }
301
302 SECTION("map_or") {
303 tl::optional<int> o1 = 21;
304 REQUIRE((o1.map_or([](int x) { return x * 2; }, 13)) == 42);
305
306 tl::optional<int> o2;
307 REQUIRE((o2.map_or([](int x) { return x * 2; }, 13)) == 13);
308 }
309
310 SECTION("map_or_else") {
311 tl::optional<int> o1 = 21;
312 REQUIRE((o1.map_or_else([](int x) { return x * 2; }, [] { return 13; })) ==
313 42);
314
315 tl::optional<int> o2;
316 REQUIRE((o2.map_or_else([](int x) { return x * 2; }, [] { return 13; })) ==
317 13);
318 }
319
320 SECTION("take") {
321 tl::optional<int> o1 = 42;
322 REQUIRE(*o1.take() == 42);
323 REQUIRE(!o1);
324
325 tl::optional<int> o2;
326 REQUIRE(!o2.take());
327 REQUIRE(!o2);
328 }
329
330 struct foo {
331 void non_const() {}
332 };
333
334#if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \
335 !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55)
336 SECTION("Issue #1") {
337 tl::optional<foo> f = foo{};
338 auto l = [](auto &&x) { x.non_const(); };
339 f.map(l);
340 }
341#endif
342
343 struct overloaded {
344 tl::optional<int> operator()(foo &) { return 0; }
345 tl::optional<std::string> operator()(const foo &) { return ""; }
346 };
347
348 SECTION("Issue #2") {
349 tl::optional<foo> f = foo{};
350 auto x = f.and_then(overloaded{});
351 }
352};