1 /* Unit testing for outcomes
2 (C) 2013-2022 Niall Douglas <http://www.nedproductions.biz/> (8 commits)
5 Boost Software License - Version 1.0 - August 17th, 2003
7 Permission is hereby granted, free of charge, to any person or organization
8 obtaining a copy of the software and accompanying documentation covered by
9 this license (the "Software") to use, reproduce, display, distribute,
10 execute, and transmit the Software, and to prepare derivative works of the
11 Software, and to permit third-parties to whom the Software is furnished to
12 do so, all subject to the following:
14 The copyright notices in the Software and this entire statement, including
15 the above license grant, this restriction and the following disclaimer,
16 must be included in all copies of the Software, in whole or in part, and
17 all derivative works of the Software, unless such copies or derivative
18 works are solely in the form of machine-executable object code generated by
19 a source language processor.
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
24 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
25 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
26 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 DEALINGS IN THE SOFTWARE.
30 #include <boost/outcome/experimental/status_result.hpp>
32 template <class T
, class S
= BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::system_code
, class NoValuePolicy
= BOOST_OUTCOME_V2_NAMESPACE::experimental::policy::default_status_result_policy
<T
, S
>> using result
= BOOST_OUTCOME_V2_NAMESPACE::experimental::status_result
<T
, S
, NoValuePolicy
>;
33 using BOOST_OUTCOME_V2_NAMESPACE::in_place_type
;
35 #include <boost/test/unit_test.hpp>
36 #include <boost/test/unit_test_monitor.hpp>
41 #ifndef BOOST_NO_EXCEPTIONS
42 // Custom error type with payload
45 BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::errc ec
{BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::errc::success
};
46 const char *str
{nullptr};
48 payload(BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::errc _ec
, const char *_str
)
54 struct payload_exception
: std::exception
56 const char *_what
{nullptr};
57 explicit payload_exception(const char *what
)
61 virtual const char *what() const noexcept override final
{ return _what
; } // NOLINT
64 class _payload_domain
;
65 using status_code_payload
= BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code
<_payload_domain
>;
66 class _payload_domain
: public BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code_domain
68 template <class> friend class status_code
;
69 using _base
= BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code_domain
;
72 using value_type
= payload
;
73 using string_ref
= _base::string_ref
;
76 constexpr _payload_domain() noexcept
: _base(0x7b782c8f935e34ba) {}
78 static inline constexpr const _payload_domain
&get();
80 virtual _base::string_ref
name() const noexcept override final
{ return string_ref("payload domain"); } // NOLINT
82 virtual bool _do_failure(const BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code
<void> &code
) const noexcept override final
// NOLINT
84 assert(code
.domain() == *this); // NOLINT
85 return static_cast<const status_code_payload
&>(code
).value().ec
!= BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::errc::success
; // NOLINT
87 virtual bool _do_equivalent(const BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code
<void> &code1
, const BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code
<void> &code2
) const noexcept override final
// NOLINT
89 assert(code1
.domain() == *this); // NOLINT
90 const auto &c1
= static_cast<const status_code_payload
&>(code1
); // NOLINT
91 if(code2
.domain() == *this)
93 const auto &c2
= static_cast<const status_code_payload
&>(code2
); // NOLINT
94 return c1
.value().ec
== c2
.value().ec
;
98 virtual BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::generic_code
_generic_code(const BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code
<void> &code
) const noexcept override final
// NOLINT
100 assert(code
.domain() == *this); // NOLINT
101 return static_cast<const status_code_payload
&>(code
).value().ec
; // NOLINT
103 virtual _base::string_ref
_do_message(const BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code
<void> &code
) const noexcept override final
// NOLINT
105 assert(code
.domain() == *this); // NOLINT
106 const auto &c
= static_cast<const status_code_payload
&>(code
); // NOLINT
107 return string_ref(BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::detail::generic_code_message(c
.value().ec
));
109 virtual void _do_throw_exception(const BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code
<void> &code
) const override final
// NOLINT
111 assert(code
.domain() == *this); // NOLINT
112 const auto &c
= static_cast<const status_code_payload
&>(code
); // NOLINT
113 throw payload_exception(c
.value().str
);
116 constexpr _payload_domain payload_domain
;
117 inline constexpr const _payload_domain
&_payload_domain::get()
119 return payload_domain
;
121 inline status_code_payload
make_status_code(payload c
) noexcept
123 return status_code_payload(BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::in_place
, c
);
127 BOOST_OUTCOME_AUTO_TEST_CASE(works_status_code_result
, "Tests that the result with status_code works as intended")
129 using namespace BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE
;
132 result
<int> m(generic_code
{errc::bad_address
});
134 BOOST_CHECK(!m
.has_value());
135 BOOST_CHECK(m
.has_error());
136 // BOOST_CHECK(!m.has_exception());
137 BOOST_CHECK_THROW(m
.value(), generic_error
);
138 BOOST_CHECK_NO_THROW(m
.error());
141 result
<void> m(generic_code
{errc::bad_address
});
143 BOOST_CHECK(!m
.has_value());
144 BOOST_CHECK(m
.has_error());
145 // BOOST_CHECK(!m.has_exception());
146 BOOST_CHECK_THROW(([&m
]() -> void { return m
.value(); }()), generic_error
);
147 BOOST_CHECK_NO_THROW(m
.error());
152 BOOST_CHECK(m
.has_value());
153 BOOST_CHECK(!m
.has_error());
154 // BOOST_CHECK(!m.has_exception());
155 BOOST_CHECK(m
.value() == 5);
157 BOOST_CHECK(m
.value() == 6);
160 result
<bool> m(false);
162 BOOST_CHECK(m
.has_value());
163 BOOST_CHECK(!m
.has_error());
164 // BOOST_CHECK(!m.has_exception());
165 BOOST_CHECK(m
.value() == false);
167 BOOST_CHECK(m
.value() == true);
169 { // moves do not clear state
170 result
<std::string
> m("niall");
172 BOOST_CHECK(m
.has_value());
173 BOOST_CHECK(!m
.has_error());
174 // BOOST_CHECK(!m.has_exception());
175 BOOST_CHECK(m
.value() == "niall");
177 BOOST_CHECK(m
.value() == "NIALL");
178 auto temp(std::move(m
).value());
179 BOOST_CHECK(temp
== "NIALL");
180 BOOST_CHECK(m
.value().empty()); // NOLINT
183 result
<void> m(in_place_type
<void>);
185 BOOST_CHECK(m
.has_value());
186 BOOST_CHECK(!m
.has_error());
187 // BOOST_CHECK(!m.has_exception());
188 BOOST_CHECK_NO_THROW(m
.value()); // works, but type returned is unusable
191 error
ec(errc::no_link
);
192 result
<int> m(ec
.clone());
194 BOOST_CHECK(!m
.has_value());
195 BOOST_CHECK(m
.has_error());
196 // BOOST_CHECK(!m.has_exception());
197 BOOST_CHECK_THROW(m
.value(), generic_error
);
198 BOOST_CHECK(m
.error() == ec
);
201 { // void, void is permitted, but is not constructible
202 result
<void, void> *m
= nullptr;
208 // Deliberately define non-trivial operations
213 udt(udt
&&o
) noexcept
: _v(o
._v
) {}
214 udt(const udt
&o
) // NOLINT
218 udt
&operator=(udt
&&o
) noexcept
223 udt
&operator=(const udt
&o
) // NOLINT
230 // No default construction, no copy nor move
234 udt2(udt2
&&) = delete;
235 udt2(const udt2
&) = delete;
236 udt2
&operator=(udt2
&&) = delete;
237 udt2
&operator=(const udt2
&) = delete;
238 explicit udt2(int /*unused*/) {}
241 // Can only be constructed via multiple args
245 udt3(udt3
&&) = delete;
246 udt3(const udt3
&) = delete;
247 udt3
&operator=(udt3
&&) = delete;
248 udt3
&operator=(const udt3
&) = delete;
249 explicit udt3(int /*unused*/, const char * /*unused*/, std::nullptr_t
/*unused*/) {}
254 result
<int> b(generic_code
{errc::invalid_argument
});
255 std::cout
<< sizeof(a
) << std::endl
; // 32 bytes
261 #ifndef BOOST_NO_EXCEPTIONS
265 std::cerr
<< "fail" << std::endl
;
268 catch(const generic_error
&e
)
270 BOOST_CHECK(!strcmp(e
.what(), b
.error().message().c_str()));
273 static_assert(!std::is_default_constructible
<decltype(a
)>::value
, "");
274 static_assert(!std::is_nothrow_default_constructible
<decltype(a
)>::value
, "");
275 static_assert(!std::is_copy_constructible
<decltype(a
)>::value
, "");
276 // Quality of implementation of std::optional is poor :(
277 #ifndef TESTING_WG21_EXPERIMENTAL_RESULT
278 static_assert(!std::is_trivially_copy_constructible
<decltype(a
)>::value
, "");
279 static_assert(!std::is_nothrow_copy_constructible
<decltype(a
)>::value
, "");
280 static_assert(!std::is_copy_assignable
<decltype(a
)>::value
, "");
281 static_assert(!std::is_trivially_copy_assignable
<decltype(a
)>::value
, "");
282 static_assert(!std::is_nothrow_copy_assignable
<decltype(a
)>::value
, "");
284 static_assert(!std::is_trivially_destructible
<decltype(a
)>::value
, "");
285 static_assert(std::is_nothrow_destructible
<decltype(a
)>::value
, "");
287 // Test void compiles
288 result
<void> c(in_place_type
<void>);
290 // Test a standard udt compiles
291 result
<udt
> d(in_place_type
<udt
>);
292 static_assert(!std::is_default_constructible
<decltype(d
)>::value
, "");
293 static_assert(!std::is_nothrow_default_constructible
<decltype(d
)>::value
, "");
294 static_assert(!std::is_copy_constructible
<decltype(d
)>::value
, "");
295 static_assert(!std::is_trivially_copy_constructible
<decltype(d
)>::value
, "");
296 static_assert(!std::is_nothrow_copy_constructible
<decltype(d
)>::value
, "");
297 static_assert(!std::is_copy_assignable
<decltype(d
)>::value
, "");
298 static_assert(!std::is_trivially_copy_assignable
<decltype(d
)>::value
, "");
299 static_assert(!std::is_nothrow_copy_assignable
<decltype(d
)>::value
, "");
300 static_assert(std::is_move_assignable
<decltype(d
)>::value
, "");
301 static_assert(!std::is_trivially_move_assignable
<decltype(d
)>::value
, "");
302 static_assert(std::is_nothrow_move_assignable
<decltype(d
)>::value
, "");
303 static_assert(!std::is_trivially_destructible
<decltype(d
)>::value
, "");
304 static_assert(std::is_nothrow_destructible
<decltype(d
)>::value
, "");
306 // Test a highly pathological udt compiles
307 result
<udt2
> e(in_place_type
<udt2
>, 5);
308 // result<udt2> e2(e);
309 static_assert(!std::is_default_constructible
<decltype(e
)>::value
, "");
310 static_assert(!std::is_nothrow_default_constructible
<decltype(e
)>::value
, "");
311 static_assert(!std::is_copy_constructible
<decltype(e
)>::value
, "");
312 static_assert(!std::is_trivially_copy_constructible
<decltype(e
)>::value
, "");
313 static_assert(!std::is_nothrow_copy_constructible
<decltype(e
)>::value
, "");
314 static_assert(!std::is_copy_assignable
<decltype(e
)>::value
, "");
315 static_assert(!std::is_trivially_copy_assignable
<decltype(e
)>::value
, "");
316 static_assert(!std::is_nothrow_copy_assignable
<decltype(e
)>::value
, "");
317 static_assert(!std::is_move_assignable
<decltype(e
)>::value
, "");
318 static_assert(!std::is_trivially_move_assignable
<decltype(e
)>::value
, "");
319 static_assert(!std::is_nothrow_move_assignable
<decltype(e
)>::value
, "");
321 // Test a udt which can only be constructed in place compiles
322 result
<udt3
> g(in_place_type
<udt3
>, 5, static_cast<const char *>("niall"), nullptr);
323 // Does converting inplace construction also work?
324 result
<udt3
> h(5, static_cast<const char *>("niall"), nullptr);
325 result
<udt3
> i(generic_code
{errc::not_enough_memory
});
326 BOOST_CHECK(h
.has_value());
327 BOOST_CHECK(i
.has_error());
330 // Test direct use of error code enum works
332 constexpr result
<int, errc
, BOOST_OUTCOME_V2_NAMESPACE::policy::all_narrow
> a(5), b(errc::invalid_argument
);
333 static_assert(a
.value() == 5, "a is not 5");
334 static_assert(b
.error() == errc::invalid_argument
, "b is not errored");
337 #ifndef BOOST_NO_EXCEPTIONS
338 // Test payload facility
340 const char *niall
= "niall";
341 result
<int, status_code_payload
> b
{payload
{errc::invalid_argument
, niall
}};
347 catch(const payload_exception
&e
)
349 BOOST_CHECK(!strcmp(e
.what(), niall
));