]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/outcome/test/tests/core-result.cpp
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / boost / libs / outcome / test / tests / core-result.cpp
CommitLineData
92f5a8d4 1/* Unit testing for outcomes
f67539c2 2(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (30 commits)
92f5a8d4
TL
3
4
5Boost Software License - Version 1.0 - August 17th, 2003
6
7Permission is hereby granted, free of charge, to any person or organization
8obtaining a copy of the software and accompanying documentation covered by
9this license (the "Software") to use, reproduce, display, distribute,
10execute, and transmit the Software, and to prepare derivative works of the
11Software, and to permit third-parties to whom the Software is furnished to
12do so, all subject to the following:
13
14The copyright notices in the Software and this entire statement, including
15the above license grant, this restriction and the following disclaimer,
16must be included in all copies of the Software, in whole or in part, and
17all derivative works of the Software, unless such copies or derivative
18works are solely in the form of machine-executable object code generated by
19a source language processor.
20
21THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
24SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
25FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
26ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27DEALINGS IN THE SOFTWARE.
28*/
29
30#ifdef TESTING_WG21_EXPERIMENTAL_RESULT
31#include <boost/outcome/experimental/result.hpp>
32#define BOOST_OUTCOME_AUTO_TEST_CASE(...) BOOST_AUTO_TEST_CASE(__VA_ARGS__)
33#else
34#include <boost/outcome/result.hpp>
35#endif
36#include <boost/test/unit_test.hpp>
37#include <boost/test/unit_test_monitor.hpp>
38
39#include <iostream>
40
41#ifndef BOOST_NO_EXCEPTIONS
42// Custom error type with payload
43struct payload
44{
45 boost::system::error_code ec;
46 const char *str{nullptr};
47 payload() = default;
48 payload(boost::system::errc::errc_t _ec, const char *_str)
49 : ec(make_error_code(_ec))
50 , str(_str)
51 {
52 }
53};
54struct payload_exception : std::runtime_error
55{
56 explicit payload_exception(const char *what)
57 : std::runtime_error(what)
58 {
59 }
60};
61inline const boost::system::error_code &make_error_code(const payload &p)
62{
63 return p.ec;
64}
65inline void outcome_throw_as_system_error_with_payload(const payload &p)
66{
67 throw payload_exception(p.str);
68}
69#endif
70
71BOOST_OUTCOME_AUTO_TEST_CASE(works_result, "Tests that the result works as intended")
72{
73#ifdef TESTING_WG21_EXPERIMENTAL_RESULT
74 using namespace std::experimental;
75 using std::in_place_type;
76#else
77 using namespace BOOST_OUTCOME_V2_NAMESPACE;
78#endif
79
80 static_assert(std::is_constructible<result<long>, int>::value, "Sanity check that monad can be constructed from a value_type");
81 static_assert(!std::is_constructible<result<result<long>>, int>::value, "Sanity check that outer monad can be constructed from an inner monad's value_type");
82 static_assert(!std::is_constructible<result<result<result<long>>>, int>::value, "Sanity check that outer monad can be constructed from an inner inner monad's value_type");
83 static_assert(!std::is_constructible<result<result<result<result<long>>>>, int>::value, "Sanity check that outer monad can be constructed from an inner inner monad's value_type");
84
85 static_assert(std::is_constructible<result<int>, result<long>>::value, "Sanity check that compatible monads can be constructed from one another");
86 static_assert(std::is_constructible<result<result<int>>, result<long>>::value, "Sanity check that outer monad can be constructed from a compatible monad");
87 static_assert(!std::is_constructible<result<result<result<int>>>, result<long>>::value, "Sanity check that outer monad can be constructed from a compatible monad up to two nestings deep");
88 static_assert(!std::is_constructible<result<result<result<result<int>>>>, result<long>>::value, "Sanity check that outer monad can be constructed from a compatible monad three or more nestings deep");
89 static_assert(!std::is_constructible<result<std::string>, result<int>>::value, "Sanity check that incompatible monads cannot be constructed from one another");
90
91#ifndef TESTING_WG21_EXPERIMENTAL_RESULT
92 static_assert(std::is_constructible<result<int>, result<void>>::value, "Sanity check that all monads can be constructed from a void monad");
93 static_assert(std::is_constructible<result<result<int>>, result<void>>::value, "Sanity check that outer monad can be constructed from a compatible monad");
94 static_assert(std::is_constructible<result<result<result<int>>>, result<void>>::value, "Sanity check that outer monad can be constructed from a compatible monad up to two nestings deep");
95 static_assert(!std::is_constructible<result<void>, result<int>>::value, "Sanity check that incompatible monads cannot be constructed from one another");
96#endif
97 static_assert(std::is_void<result<void>::value_type>::value, "Sanity check that result<void> has a void value_type");
98#ifndef TESTING_WG21_EXPERIMENTAL_RESULT
99 static_assert(std::is_void<result<void, void>::error_type>::value, "Sanity check that result<void, void> has a void error_type");
100#endif
101
102 static_assert(std::is_same<result<int>::value_type, int>::value, "Sanity check that result<int> has a int value_type");
103 static_assert(std::is_same<result<int>::error_type, boost::system::error_code>::value, "Sanity check that result<int> has a error_code error_type");
104
105
106 { // errored int
107 result<int> m(boost::system::errc::bad_address);
108 BOOST_CHECK(!m);
109 BOOST_CHECK(!m.has_value());
110 BOOST_CHECK(m.has_error());
111 // BOOST_CHECK(!m.has_exception());
112 BOOST_CHECK_THROW(m.value(), boost::system::system_error);
113 BOOST_CHECK_NO_THROW(m.error());
114 }
115 { // errored void
116 result<void> m(boost::system::errc::bad_address);
117 BOOST_CHECK(!m);
118 BOOST_CHECK(!m.has_value());
119 BOOST_CHECK(m.has_error());
120// BOOST_CHECK(!m.has_exception());
121#ifndef TESTING_WG21_EXPERIMENTAL_RESULT
122 BOOST_CHECK_THROW(([&m]() -> void { return m.value(); }()), boost::system::system_error);
123#endif
124 BOOST_CHECK_NO_THROW(m.error());
125 }
126 { // valued int
127 result<int> m(5);
128 BOOST_CHECK(m);
129 BOOST_CHECK(m.has_value());
130 BOOST_CHECK(!m.has_error());
131 // BOOST_CHECK(!m.has_exception());
132 BOOST_CHECK(m.value() == 5);
133 m.value() = 6;
134 BOOST_CHECK(m.value() == 6);
135 BOOST_CHECK_THROW(m.error(), bad_result_access);
136 }
137 { // valued bool
138 result<bool> m(false);
139 BOOST_CHECK(m);
140 BOOST_CHECK(m.has_value());
141 BOOST_CHECK(!m.has_error());
142 // BOOST_CHECK(!m.has_exception());
143 BOOST_CHECK(m.value() == false);
144 m.value() = true;
145 BOOST_CHECK(m.value() == true);
146 BOOST_CHECK_THROW(m.error(), bad_result_access);
147 }
148 { // moves do not clear state
149 result<std::string> m("niall");
150 BOOST_CHECK(m);
151 BOOST_CHECK(m.has_value());
152 BOOST_CHECK(!m.has_error());
153 // BOOST_CHECK(!m.has_exception());
154 BOOST_CHECK(m.value() == "niall");
155 m.value() = "NIALL";
156 BOOST_CHECK(m.value() == "NIALL");
157 auto temp(std::move(m).value());
158 BOOST_CHECK(temp == "NIALL");
159 BOOST_CHECK(m.value().empty()); // NOLINT
160 }
161 { // valued void
162 result<void> m(in_place_type<void>);
163 BOOST_CHECK(m);
164 BOOST_CHECK(m.has_value());
165 BOOST_CHECK(!m.has_error());
166 // BOOST_CHECK(!m.has_exception());
167 BOOST_CHECK_NO_THROW(m.value()); // works, but type returned is unusable
168 BOOST_CHECK_THROW(m.error(), bad_result_access);
169 }
170 { // errored
171 boost::system::error_code ec(5, boost::system::system_category());
172 result<int> m(ec);
173 BOOST_CHECK(!m);
174 BOOST_CHECK(!m.has_value());
175 BOOST_CHECK(m.has_error());
176 // BOOST_CHECK(!m.has_exception());
177 BOOST_CHECK_THROW(m.value(), boost::system::system_error);
178 BOOST_CHECK(m.error() == ec);
179 }
180#if !defined(__APPLE__) || defined(__cpp_exceptions)
181 { // errored, custom
182 boost::system::error_code ec(5, boost::system::system_category());
183 auto e = boost::copy_exception(boost::system::system_error(ec)); // NOLINT
184 result<int, boost::exception_ptr> m(e);
185 BOOST_CHECK(!m);
186 BOOST_CHECK(!m.has_value());
187 BOOST_CHECK(m.has_error());
188 // BOOST_CHECK(!m.has_exception());
189 BOOST_CHECK_THROW(m.value(), boost::system::system_error);
190 BOOST_CHECK(m.error() == e);
191 }
192#endif
193#ifndef TESTING_WG21_EXPERIMENTAL_RESULT
194 { // custom error type
195 struct Foo
196 {
197 };
198 result<int, Foo> m(in_place_type<Foo>);
199 BOOST_CHECK(!m);
200 BOOST_CHECK(!m.has_value());
201 BOOST_CHECK(m.has_error());
202 // BOOST_CHECK(!m.has_exception());
203 // BOOST_CHECK_NO_THROW(m.value());
204 // BOOST_CHECK_NO_THROW(m.error());
205 }
206 if(false) // NOLINT
207 { // void, void is permitted, but is not constructible
208 result<void, void> *m = nullptr;
209 m->value();
210 m->error();
211 }
212#endif
213
214 {
215 // Deliberately define non-trivial operations
216 struct udt
217 {
218 int _v{0};
219 udt() = default;
220 udt(udt &&o) noexcept : _v(o._v) {}
221 udt(const udt &o) // NOLINT
222 : _v(o._v)
223 {
224 }
225 udt &operator=(udt &&o) noexcept
226 {
227 _v = o._v;
228 return *this;
229 }
230 udt &operator=(const udt &o) // NOLINT
231 {
232 _v = o._v;
233 return *this;
234 }
235 ~udt() { _v = 0; }
236 };
237 // No default construction, no copy nor move
238 struct udt2
239 {
240 udt2() = delete;
241 udt2(udt2 &&) = delete;
242 udt2(const udt2 &) = delete;
243 udt2 &operator=(udt2 &&) = delete;
244 udt2 &operator=(const udt2 &) = delete;
245 explicit udt2(int /*unused*/) {}
246 ~udt2() = default;
247 };
248 // Can only be constructed via multiple args
249 struct udt3
250 {
251 udt3() = delete;
252 udt3(udt3 &&) = delete;
253 udt3(const udt3 &) = delete;
254 udt3 &operator=(udt3 &&) = delete;
255 udt3 &operator=(const udt3 &) = delete;
256 explicit udt3(int /*unused*/, const char * /*unused*/, std::nullptr_t /*unused*/) {}
257 ~udt3() = default;
258 };
259
260
261 result<int> a(5);
262 result<int> b(make_error_code(boost::system::errc::invalid_argument));
263 std::cout << sizeof(a) << std::endl; // 32 bytes
264 if(false) // NOLINT
265 {
266 b.assume_value();
267 a.assume_error();
268 }
269#ifndef BOOST_NO_EXCEPTIONS
270 try
271 {
272 b.value();
273 std::cerr << "fail" << std::endl;
274 std::terminate();
275 }
276 catch(const boost::system::system_error & /*unused*/)
277 {
278 }
279#endif
280 static_assert(!std::is_default_constructible<decltype(a)>::value, "");
281 static_assert(!std::is_nothrow_default_constructible<decltype(a)>::value, "");
282 static_assert(std::is_copy_constructible<decltype(a)>::value, "");
283// Quality of implementation of std::optional is poor :(
284#ifndef TESTING_WG21_EXPERIMENTAL_RESULT
285 static_assert(std::is_trivially_copy_constructible<decltype(a)>::value, "");
286 static_assert(std::is_nothrow_copy_constructible<decltype(a)>::value, "");
287 static_assert(std::is_copy_assignable<decltype(a)>::value, "");
288 static_assert(std::is_trivially_copy_assignable<decltype(a)>::value, "");
289 static_assert(std::is_nothrow_copy_assignable<decltype(a)>::value, "");
290#endif
291 static_assert(std::is_trivially_destructible<decltype(a)>::value, "");
292 static_assert(std::is_nothrow_destructible<decltype(a)>::value, "");
293
294 // Test void compiles
295 result<void> c(in_place_type<void>);
296 result<void> c2(c);
297 (void) c2;
298
299 // Test a standard udt compiles
300 result<udt> d(in_place_type<udt>);
301 result<udt> d2(d);
302 static_assert(!std::is_default_constructible<decltype(d)>::value, "");
303 static_assert(!std::is_nothrow_default_constructible<decltype(d)>::value, "");
304 static_assert(std::is_copy_constructible<decltype(d)>::value, "");
305 static_assert(!std::is_trivially_copy_constructible<decltype(d)>::value, "");
306 static_assert(!std::is_nothrow_copy_constructible<decltype(d)>::value, "");
307 static_assert(std::is_copy_assignable<decltype(d)>::value, "");
308 static_assert(!std::is_trivially_copy_assignable<decltype(d)>::value, "");
309 static_assert(!std::is_nothrow_copy_assignable<decltype(d)>::value, "");
310 static_assert(std::is_move_assignable<decltype(d)>::value, "");
311 static_assert(!std::is_trivially_move_assignable<decltype(d)>::value, "");
312 static_assert(std::is_nothrow_move_assignable<decltype(d)>::value, "");
313 static_assert(!std::is_trivially_destructible<decltype(d)>::value, "");
314 static_assert(std::is_nothrow_destructible<decltype(d)>::value, "");
315
316 // Test a highly pathological udt compiles
317 result<udt2> e(in_place_type<udt2>, 5);
318 // result<udt2> e2(e);
319 static_assert(!std::is_default_constructible<decltype(e)>::value, "");
320 static_assert(!std::is_nothrow_default_constructible<decltype(e)>::value, "");
321 static_assert(!std::is_copy_constructible<decltype(e)>::value, "");
322 static_assert(!std::is_trivially_copy_constructible<decltype(e)>::value, "");
323 static_assert(!std::is_nothrow_copy_constructible<decltype(e)>::value, "");
324 static_assert(!std::is_copy_assignable<decltype(e)>::value, "");
325 static_assert(!std::is_trivially_copy_assignable<decltype(e)>::value, "");
326 static_assert(!std::is_nothrow_copy_assignable<decltype(e)>::value, "");
327 static_assert(!std::is_move_assignable<decltype(e)>::value, "");
328 static_assert(!std::is_trivially_move_assignable<decltype(e)>::value, "");
329 static_assert(!std::is_nothrow_move_assignable<decltype(e)>::value, "");
330
331 // Test a udt which can only be constructed in place compiles
332 result<udt3> g(in_place_type<udt3>, 5, static_cast<const char *>("niall"), nullptr);
333 // Does converting inplace construction also work?
334 result<udt3> h(5, static_cast<const char *>("niall"), nullptr);
335 result<udt3> i(ENOMEM, boost::system::generic_category());
336 BOOST_CHECK(h.has_value());
337 BOOST_CHECK(i.has_error());
338 }
339
340 // Test direct use of error code enum works
341 {
342 constexpr result<int, boost::system::errc::errc_t> a(5), b(boost::system::errc::invalid_argument);
343 static_assert(a.value() == 5, "a is not 5");
344 static_assert(b.error() == boost::system::errc::invalid_argument, "b is not errored");
345 BOOST_CHECK_THROW(b.value(), boost::system::system_error);
346 }
347
348#ifndef TESTING_WG21_EXPERIMENTAL_RESULT
349#ifndef BOOST_NO_EXCEPTIONS
350 // Test payload facility
351 {
352 const char *niall = "niall";
353 result<int, payload> b{boost::system::errc::invalid_argument, niall};
354 try
355 {
356 b.value();
357 BOOST_CHECK(false);
358 }
359 catch(const payload_exception &e)
360 {
361 BOOST_CHECK(!strcmp(e.what(), niall));
362 }
363 catch(...)
364 {
365 BOOST_CHECK(false);
366 }
367 }
368#endif
369#endif
370}