diff options
Diffstat (limited to 'src/boost/libs/outcome')
48 files changed, 6498 insertions, 0 deletions
diff --git a/src/boost/libs/outcome/CMakeLists.txt b/src/boost/libs/outcome/CMakeLists.txt new file mode 100644 index 000000000..cc49eb713 --- /dev/null +++ b/src/boost/libs/outcome/CMakeLists.txt @@ -0,0 +1,16 @@ +# Distributed under the Boost Software License, Version 1.0. +# See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt + +cmake_minimum_required(VERSION 3.5) +project(BoostOutcome LANGUAGES CXX) + +add_library(boost_outcome INTERFACE) +add_library(Boost::outcome ALIAS boost_outcome) + +target_include_directories(boost_outcome INTERFACE include) + +target_link_libraries(boost_outcome INTERFACE + Boost::config + Boost::exception + Boost::system +) diff --git a/src/boost/libs/outcome/Readme.md b/src/boost/libs/outcome/Readme.md new file mode 100644 index 000000000..163ae900d --- /dev/null +++ b/src/boost/libs/outcome/Readme.md @@ -0,0 +1,23 @@ +Build and tests passing: Linux [![Build Status](https://travis-ci.org/boostorg/outcome.svg?branch=master)](https://travis-ci.org/boostorg/outcome) + +Documentation generated from the master branch shown below (may be newer than boost.org's): http://boostorg.github.io/outcome + +This is the Boost-ified edition of standalone https://github.com/ned14/outcome. +Every commit made to standalone Outcome (develop and master branches only) gets +automatically converted and merged to here. + +Note that changes made here may not get noticed in a timely fashion. +Please try to send pull requests to https://github.com/ned14/outcome/pulls instead. + +Similarly, please report bugs to https://github.com/ned14/outcome/issues. + +This library works well in older Boosts missing Outcome. Installation into an +older Boost and running the test suite would be as follows: + +``` +cd boost/libs +git clone --depth 1 https://github.com/boostorg/outcome.git outcome +cd .. +./b2 headers +./b2 libs/outcome/test cxxflags=--std=c++14 +``` diff --git a/src/boost/libs/outcome/index.html b/src/boost/libs/outcome/index.html new file mode 100644 index 000000000..32c29efed --- /dev/null +++ b/src/boost/libs/outcome/index.html @@ -0,0 +1,4 @@ +<html> +<head><meta http-equiv="refresh" content="0; url=doc/html/index.html" /></head> +<body>Please go to <a href="doc/index.html">doc/html/index.html</a></body> +</html> diff --git a/src/boost/libs/outcome/meta/explicit-failures-markup.xml b/src/boost/libs/outcome/meta/explicit-failures-markup.xml new file mode 100644 index 000000000..d22f99564 --- /dev/null +++ b/src/boost/libs/outcome/meta/explicit-failures-markup.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<explicit-failures-markup xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/boostorg/boost/master/status/explicit-failures.xsd"> + <!-- outcome --> + <library name="outcome"> + <mark-unusable> + <toolset name="*c++98"/> + <toolset name="*c++11"/> + <toolset name="*gnu++98"/> + <toolset name="*gnu++11"/> + <toolset name="*gnu98"/> + <toolset name="*gnu11"/> + <toolset name="clang-linux-3*"/> + <toolset name="gcc-3*"/> + <toolset name="gcc-4*"/> + <toolset name="gcc-5*"/> + <toolset name="gcc-mngw-3*"/> + <toolset name="gcc-mngw-4*"/> + <toolset name="gcc-mngw-5*"/> + <toolset name="msvc-7*"/> + <toolset name="msvc-8*"/> + <toolset name="msvc-9*"/> + <toolset name="msvc-10*"/> + <toolset name="msvc-11*"/> + <toolset name="msvc-12*"/> + <toolset name="msvc-13*"/> + <toolset name="msvc-14.0"/> + <toolset name="msvc-14.0*"/> + <note author="Niall Douglas">Complete C++14 support is the minimum requirement.</note> + </mark-unusable> + <mark-unusable> + <toolset name="clang-linux-4.0~c++14"/> + <toolset name="clang-linux-5.0~c++14"/> + <toolset name="clang-linux-6.0~c++17"/> + <note author="Niall Douglas">libstdc++ 6 is the minimum version which works.</note> + </mark-unusable> + </library> +</explicit-failures-markup>
\ No newline at end of file diff --git a/src/boost/libs/outcome/meta/libraries.json b/src/boost/libs/outcome/meta/libraries.json new file mode 100644 index 000000000..de6460ec1 --- /dev/null +++ b/src/boost/libs/outcome/meta/libraries.json @@ -0,0 +1,13 @@ +{ + "key": "outcome", + "name": "Outcome", + "authors": [ "Niall Douglas" ], + "maintainers": [ "Niall Douglas" ], + "description": "A deterministic failure handling library partially simulating lightweight exceptions.", + "std": [ "proposal" ], + "category": [ + "Patterns", + "Emulation", + "Programming" + ] +} diff --git a/src/boost/libs/outcome/test/Jamfile.v2 b/src/boost/libs/outcome/test/Jamfile.v2 new file mode 100644 index 000000000..4b11a3805 --- /dev/null +++ b/src/boost/libs/outcome/test/Jamfile.v2 @@ -0,0 +1,67 @@ +# Boost.Outcome Library test Jamfile +# +# Copyright (C) 2017-2019 Niall Douglas +# +# Use, modification, and distribution is subject to the Boost Software +# License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) +# +# See http://www.boost.org/libs/outcome for documentation. + +import testing ; +import ../../config/checks/config : requires ; +import ../../predef/tools/check/predef : check require : predef-check predef-require ; + +project + : requirements + [ requires cxx14_variable_templates cxx14_constexpr ] + [ predef-require "!BOOST_COMP_GNUC" or "BOOST_COMP_GNUC >= 6.0" ] + [ predef-require "!BOOST_COMP_CLANG" or "BOOST_COMP_CLANG >= 4.0" ] + <define>BOOST_TEST_MODULE=Outcome + <library>../../test/build//boost_unit_test_framework + ; + +{ + test-suite outcome : + + [ compile-fail compile-fail/outcome-int-int-1.cpp ] + [ compile-fail compile-fail/result-int-int-1.cpp ] + [ compile-fail compile-fail/result-int-int-2.cpp ] + + [ run tests/comparison.cpp ] + [ run tests/constexpr.cpp ] + [ run tests/containers.cpp ] + [ run tests/core-outcome.cpp ] + [ run tests/core-result.cpp ] + [ run tests/default-construction.cpp ] + [ run tests/experimental-core-outcome-status.cpp ] + [ run tests/experimental-core-result-status.cpp ] + [ run tests/experimental-p0709a.cpp ] + [ run tests/fileopen.cpp ] + [ run tests/hooks.cpp ] + [ run tests/issue0007.cpp ] + [ run tests/issue0009.cpp ] + [ run tests/issue0010.cpp ] + [ run tests/issue0012.cpp ] + [ run tests/issue0016.cpp ] + [ run tests/issue0059.cpp ] + [ run tests/issue0061.cpp ] + [ run tests/issue0064.cpp ] + [ run tests/issue0065.cpp ] + [ run tests/issue0071.cpp ] + [ run tests/issue0095.cpp ] + [ run tests/issue0115.cpp ] + [ run tests/issue0116.cpp ] + [ run tests/issue0140.cpp ] + [ run tests/noexcept-propagation.cpp ] + [ run tests/propagate.cpp ] + [ run tests/serialisation.cpp ] + [ run tests/success-failure.cpp ] + [ run tests/swap.cpp ] + [ run tests/udts.cpp ] + [ run tests/value-or-error.cpp ] + + [ run expected-pass.cpp ] + + ; +} diff --git a/src/boost/libs/outcome/test/compile-fail/issue0071-fail.cpp b/src/boost/libs/outcome/test/compile-fail/issue0071-fail.cpp new file mode 100644 index 000000000..ac94c7138 --- /dev/null +++ b/src/boost/libs/outcome/test/compile-fail/issue0071-fail.cpp @@ -0,0 +1,37 @@ +/* clang-format off +(error: no matching function for call to .+::basic_result|error: no matching constructor for initialization of 'result<udt>'|cannot convert argument 1 from 'int') +clang-format on + + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License in the accompanying file +Licence.txt or at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + + +Distributed under the Boost Software License, Version 1.0. +(See accompanying file Licence.txt or copy at +http://www.boost.org/LICENSE_1_0.txt) +*/ + +#include "../../include/boost/outcome/result.hpp" + +int main() +{ + using namespace BOOST_OUTCOME_V2_NAMESPACE; + struct udt + { + explicit udt(int /*unused*/) {} + }; + // Must not be possible to implicitly initialise a result<udt> + result<udt> m(5); + return 0; +} diff --git a/src/boost/libs/outcome/test/compile-fail/outcome-int-int-1.cpp b/src/boost/libs/outcome/test/compile-fail/outcome-int-int-1.cpp new file mode 100644 index 000000000..4ee66b746 --- /dev/null +++ b/src/boost/libs/outcome/test/compile-fail/outcome-int-int-1.cpp @@ -0,0 +1,33 @@ +/* clang-format off +(use of deleted function|call to deleted constructor|attempting to reference a deleted function) +clang-format on + + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License in the accompanying file +Licence.txt or at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + + +Distributed under the Boost Software License, Version 1.0. +(See accompanying file Licence.txt or copy at +http://www.boost.org/LICENSE_1_0.txt) +*/ + +#include "../../include/boost/outcome/outcome.hpp" + +int main() +{ + using namespace BOOST_OUTCOME_V2_NAMESPACE; + // Must not be possible to initialise an outcome with same R, S and P types + outcome<int, int, int> m(5); + return 0; +} diff --git a/src/boost/libs/outcome/test/compile-fail/result-int-int-1.cpp b/src/boost/libs/outcome/test/compile-fail/result-int-int-1.cpp new file mode 100644 index 000000000..e4eb92031 --- /dev/null +++ b/src/boost/libs/outcome/test/compile-fail/result-int-int-1.cpp @@ -0,0 +1,33 @@ +/* clang-format off +(use of deleted function|call to deleted constructor|attempting to reference a deleted function) +clang-format on + + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License in the accompanying file +Licence.txt or at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + + +Distributed under the Boost Software License, Version 1.0. +(See accompanying file Licence.txt or copy at +http://www.boost.org/LICENSE_1_0.txt) +*/ + +#include "../../include/boost/outcome/result.hpp" + +int main() +{ + using namespace BOOST_OUTCOME_V2_NAMESPACE; + // Must not be possible to initialise a result with same R and S types + result<int, int> m(5); + return 0; +} diff --git a/src/boost/libs/outcome/test/compile-fail/result-int-int-2.cpp b/src/boost/libs/outcome/test/compile-fail/result-int-int-2.cpp new file mode 100644 index 000000000..35c999d0a --- /dev/null +++ b/src/boost/libs/outcome/test/compile-fail/result-int-int-2.cpp @@ -0,0 +1,33 @@ +/* clang-format off +(use of deleted function|call to deleted constructor|attempting to reference a deleted function) +clang-format on + + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License in the accompanying file +Licence.txt or at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + + +Distributed under the Boost Software License, Version 1.0. +(See accompanying file Licence.txt or copy at +http://www.boost.org/LICENSE_1_0.txt) +*/ + +#include "../../include/boost/outcome/result.hpp" + +int main() +{ + using namespace BOOST_OUTCOME_V2_NAMESPACE; + // Must not be possible to initialise a result with same R and S types + result<int, int> m(in_place_type<int>); + return 0; +} diff --git a/src/boost/libs/outcome/test/expected-pass.cpp b/src/boost/libs/outcome/test/expected-pass.cpp new file mode 100644 index 000000000..5c63b9118 --- /dev/null +++ b/src/boost/libs/outcome/test/expected-pass.cpp @@ -0,0 +1,2015 @@ +//! \file test_expected.cpp + +// Copyright Pierre Talbot 2013. +// Copyright Vicente J. Botet Escriba 2013,2014. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +//(See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + + +// Notes by ned: +// Original is at https://github.com/viboes/std-make/blob/master/test/expected/expected_pass.cpp +// This edition modified to use result with throw_bad_result_access policy +// Quite a lot of the test suite I had to disable, not because our Expected implementation is +// incorrect, but because the reference test suite is testing an Expected quite far away from +// the latest WG21 proposal paper, and we're implementing that latest edition. + +#if !defined(__GNUC__) || defined(__clang__) || __GNUC__ >= 7 + +#include <utility> + +#include <boost/outcome/iostream_support.hpp> +#include <boost/outcome/std_result.hpp> + +#define QUICKCPPLIB_BOOST_UNIT_TEST_CUSTOM_MAIN_DEFINED +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +#define JASEL_NORETURN +#ifndef BOOST_TEST +#define BOOST_TEST(expr) BOOST_CHECK(expr) +#endif +#ifndef BOOST_TEST_EQ +#define BOOST_TEST_EQ(a, b) BOOST_CHECK_EQUAL((a), (b)) +#endif +#ifndef BOOST_TEST_THROWS +#define BOOST_TEST_THROWS(expr, ex) BOOST_CHECK_THROW((expr), ex) +#endif +#ifndef BOOST_CONSTEXPR +#define BOOST_CONSTEXPR constexpr +#endif + +#ifdef _MSC_VER +#pragma warning(disable : 4127) // conditional expression is constant +#pragma warning(disable : 4244) // conversion from int to short +#endif + +namespace stde +{ +#if __cplusplus >= 201700 || _HAS_CXX17 + using in_place_t = std::in_place_t; + using std::in_place; +#else + struct in_place_t + { + explicit in_place_t() = default; + }; + constexpr in_place_t in_place{}; +#endif + + //! [expected_implementation] + /* Here is a fairly conforming implementation of P0323R3 `expected<T, E>` using `checked<T, E>`. + It passes the reference test suite for P0323R3 at + https://github.com/viboes/std-make/blob/master/test/expected/expected_pass.cpp with modifications + only to move the test much closer to the P0323R3 Expected, as the reference test suite is for a + much older proposed Expected. + + Known differences from P0323R3 in this implementation: + - `T` and `E` cannot be the same type. + - No variant storage is implemented. + */ + + namespace detail + { + template <class T, class E> using expected_result = BOOST_OUTCOME_V2_NAMESPACE::checked<T, E>; + template <class T, class E> struct enable_default_constructor : public expected_result<T, E> + { + using base = expected_result<T, E>; + using base::base; + constexpr enable_default_constructor() + : base{BOOST_OUTCOME_V2_NAMESPACE::in_place_type<T>} + { + } + }; + template <class T, class E> using select_expected_base = std::conditional_t<std::is_default_constructible<T>::value, enable_default_constructor<T, E>, expected_result<T, E>>; + } // namespace detail + template <class T, class E> class expected : public detail::select_expected_base<T, E> + { + static_assert(!std::is_same<T, E>::value, "T and E cannot be the same in this expected implementation"); + using base = detail::select_expected_base<T, E>; + + public: + // Inherit base's constructors + using base::base; + expected() = default; + + // Expected takes in_place not in_place_type + template <class... Args> + constexpr explicit expected(in_place_t /*unused*/, Args &&... args) + : base{BOOST_OUTCOME_V2_NAMESPACE::in_place_type<T>, std::forward<Args>(args)...} + { + } + + // Expected always accepts a T even if ambiguous + BOOST_OUTCOME_TEMPLATE(class U) + BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(std::is_constructible<T, U>::value)) + constexpr expected(U &&v) // NOLINT + : base{BOOST_OUTCOME_V2_NAMESPACE::in_place_type<T>, std::forward<U>(v)} + { + } + + // Expected has an emplace() modifier + template <class... Args> void emplace(Args &&... args) { *static_cast<base *>(this) = base{BOOST_OUTCOME_V2_NAMESPACE::in_place_type<T>, std::forward<Args>(args)...}; } + + // Expected has a narrow operator* and operator-> + constexpr const T &operator*() const & { return base::assume_value(); } + constexpr T &operator*() & { return base::assume_value(); } + constexpr const T &&operator*() const && { return base::assume_value(); } + constexpr T &&operator*() && { return base::assume_value(); } + constexpr const T *operator->() const { return &base::assume_value(); } + constexpr T *operator->() { return &base::assume_value(); } + + // Expected has a narrow error() observer + constexpr const E &error() const & { return base::assume_error(); } + constexpr E &error() & { return base::assume_error(); } + constexpr const E &&error() const && { return base::assume_error(); } + constexpr E &error() && { return base::assume_error(); } + }; + template <class E> class expected<void, E> : public BOOST_OUTCOME_V2_NAMESPACE::result<void, E, BOOST_OUTCOME_V2_NAMESPACE::policy::throw_bad_result_access<E, void>> + { + using base = BOOST_OUTCOME_V2_NAMESPACE::result<void, E, BOOST_OUTCOME_V2_NAMESPACE::policy::throw_bad_result_access<E, void>>; + + public: + // Inherit base constructors + using base::base; + + // Expected has a narrow operator* and operator-> + constexpr void operator*() const { base::assume_value(); } + constexpr void operator->() const { base::assume_value(); } + }; + template <class E> using unexpected = BOOST_OUTCOME_V2_NAMESPACE::failure_type<E>; + template <class E> unexpected<E> make_unexpected(E &&arg) { return BOOST_OUTCOME_V2_NAMESPACE::failure<E>(std::forward<E>(arg)); } + template <class E, class... Args> unexpected<E> make_unexpected(Args &&... args) { return BOOST_OUTCOME_V2_NAMESPACE::failure<E>(std::forward<Args>(args)...); } + template <class E> using bad_expected_access = BOOST_OUTCOME_V2_NAMESPACE::bad_result_access_with<E>; + //! [expected_implementation] + + // Not actually part of the Expected proposal, but needed to pass the test + template <typename T> using exception_or = expected<T, std::exception_ptr>; +} // namespace stde + +template <class T> using expected_sc = stde::expected<T, std::error_code>; + +struct NoDefaultConstructible +{ + NoDefaultConstructible() = delete; + NoDefaultConstructible(int /*unused*/) {} // NOLINT +}; + +struct NoCopyConstructible +{ + NoCopyConstructible() = default; + NoCopyConstructible(NoCopyConstructible const &) = delete; + NoCopyConstructible(NoCopyConstructible &&) noexcept = default; +}; +struct NoMoveConstructible +{ + NoMoveConstructible() = default; + NoMoveConstructible(NoMoveConstructible const &) noexcept = default; + NoMoveConstructible(NoMoveConstructible &&) = delete; + NoMoveConstructible &operator=(NoMoveConstructible const &) noexcept = default; + NoMoveConstructible &operator=(NoMoveConstructible &&) = delete; +}; + +enum State +{ + sDefaultConstructed, + sValueCopyConstructed, + sValueMoveConstructed, + sCopyConstructed, + sMoveConstructed, + sMoveAssigned, + sCopyAssigned, + sValueCopyAssigned, + sValueMoveAssigned, + sMovedFrom, + sValueConstructed +}; + +struct OracleVal +{ + State s{sValueConstructed}; + int i; + constexpr OracleVal(int i_ = 0) // NOLINT + : i(i_) + { + } +}; + +struct Oracle +{ + State s{sDefaultConstructed}; + OracleVal val; + + Oracle() = default; + Oracle(const OracleVal &v) // NOLINT + : s(sValueCopyConstructed), + val(v) + { + } + Oracle(OracleVal &&v) noexcept : s(sValueMoveConstructed), val(v) { v.s = sMovedFrom; } // NOLINT + Oracle(const Oracle &o) + : s(sCopyConstructed) + , val(o.val) + { + } + Oracle(Oracle &&o) noexcept : s(sMoveConstructed), val(std::move(o.val)) { o.s = sMovedFrom; } // NOLINT + + Oracle &operator=(const OracleVal &v) + { + s = sValueCopyConstructed; + val = v; + return *this; + } + Oracle &operator=(OracleVal &&v) noexcept + { + s = sValueMoveConstructed; + val = std::move(v); // NOLINT + v.s = sMovedFrom; + return *this; + } + Oracle &operator=(const Oracle &o) + { + s = sCopyConstructed; + val = o.val; + return *this; + } + Oracle &operator=(Oracle &&o) noexcept + { + s = sMoveConstructed; + val = std::move(o.val); // NOLINT + o.s = sMovedFrom; + return *this; + } +}; + +struct Guard +{ + std::string val; + Guard() = default; + explicit Guard(std::string s, int /*unused*/ = 0) + : val(std::move(s)) + { + } + Guard(const Guard &) = delete; + Guard(Guard &&) = delete; + void operator=(const Guard &) = delete; + void operator=(Guard &&) = delete; +}; + +struct ExplicitStr +{ + std::string s; + explicit ExplicitStr(const char *chp) + : s(chp) + { + } +}; + +struct Date +{ + int i; + Date() = delete; + Date(int i_) noexcept : i{i_} {} // NOLINT + Date(Date &&d) noexcept : i(d.i) { d.i = 0; } + Date(const Date &) = delete; + Date &operator=(const Date &) = delete; + Date &operator=(Date &&d) noexcept + { + i = d.i; + d.i = 0; + return *this; + } +}; + +struct TExcept +{ + int i; + TExcept() = delete; + TExcept(int i_) // NOLINT + : i{i_} + { + } + TExcept(TExcept &&d) + : i(d.i) + { + d.i = 0; + } + TExcept(const TExcept &) = delete; + TExcept &operator=(const TExcept &) = delete; + TExcept &operator=(TExcept &&d) + { + i = d.i; + d.i = 0; + return *this; + } +}; + +template <class T> struct MoveAware +{ + T val; + bool moved; + MoveAware(T val_) // NOLINT + : val(val_), + moved(false) + { + } + MoveAware(MoveAware const &) = delete; + MoveAware(MoveAware &&rhs) + : val(rhs.val) + , moved(rhs.moved) + { + rhs.moved = true; + } + MoveAware &operator=(MoveAware const &) = delete; + MoveAware &operator=(MoveAware &&rhs) + { + val = (rhs.val); + moved = (rhs.moved); + rhs.moved = true; + return *this; + } +}; + +struct OverloadedAddressOf +{ + OverloadedAddressOf() = default; + OverloadedAddressOf *operator&() const { return nullptr; } +}; + +// using namespace boost; +// using namespace boost::functional; + +class test_exception : public std::exception +{ +}; + +int throwing_fun() +{ + throw test_exception(); +} +int nothrowing_fun() +{ + return 4; +} + +JASEL_NORETURN void void_throwing_fun() +{ + throw test_exception(); +} +void do_nothing_fun() +{ +} + +void except_default_constructor() +{ + // From value constructor. + expected_sc<int> e{}; + try + { + int i = e.value(); + (void) i; + BOOST_TEST(true); + } + catch(...) + { + BOOST_TEST(false); + }; + BOOST_TEST(e.has_value()); + BOOST_TEST(e); + BOOST_TEST(static_cast<bool>(e)); +} + + +void except_default_constructor_error_code() +{ + // From value constructor. + stde::expected<int, std::error_code> e; + BOOST_TEST(e.has_value()); + BOOST_TEST(e); + BOOST_TEST(static_cast<bool>(e)); +} + +void except_default_constructor_constexpr() +{ + // From value constructor. + BOOST_CONSTEXPR stde::expected<int, long> e; + BOOST_TEST(e.has_value()); +} + +void expected_from_value() +{ + // using T = int; + using E = std::error_code; + + // static_assert(noexcept(stde::adl::swap_impl(std::declval<T &>(), std::declval<T &>())), ""); + static_assert(std::is_nothrow_copy_constructible<E>::value, ""); + // static_assert(noexcept(stde::adl::swap_impl(std::declval<E &>(), std::declval<E &>())), ""); + + static_assert(std::is_nothrow_copy_constructible<expected_sc<int>>::value, ""); + static_assert(std::is_nothrow_copy_assignable<expected_sc<int>>::value, ""); + static_assert(std::is_nothrow_move_constructible<expected_sc<int>>::value, ""); + static_assert(std::is_nothrow_move_assignable<expected_sc<int>>::value, ""); + + // From value constructor. + expected_sc<int> e(5); + // BOOST_REQUIRE_NO_THROW(e.value()); + BOOST_TEST_EQ(e.value(), 5); + BOOST_TEST_EQ(*e, 5); + BOOST_TEST(e.has_value()); + BOOST_TEST(static_cast<bool>(e)); +} + +void expected_from_value2() +{ + // From value constructor. + expected_sc<int> e(5); + e = {}; + BOOST_TEST(e.has_value()); + BOOST_TEST_EQ(e.value(), 0); +} + +void expected_from_cnv_value() +{ + OracleVal v; + expected_sc<Oracle> e(v); + // BOOST_REQUIRE_NO_THROW(e.value()); + BOOST_TEST(!!e); + BOOST_TEST(e.has_value()); + BOOST_TEST(bool(e)); + BOOST_TEST_EQ(e.value().s, sValueCopyConstructed); + BOOST_TEST_EQ(v.s, sValueConstructed); + + expected_sc<Oracle> e2(std::move(v)); // NOLINT + // BOOST_REQUIRE_NO_THROW(e2.value()); + BOOST_TEST(!!e2); + BOOST_TEST(e2.has_value()); + BOOST_TEST(bool(e2)); + BOOST_TEST_EQ(e2.value().s, sValueMoveConstructed); + BOOST_TEST_EQ(v.s, sMovedFrom); +} + +struct NDCE // no default constructor +{ // (no default date exists) + explicit NDCE(int /*unused*/) {} +}; + +void except_constructor_NDCE() +{ + expected_sc<NDCE> e{NDCE{1}}; + BOOST_TEST(e.has_value()); +} +struct NDC // no default constructor +{ // (no default date exists) + NDC(int /*unused*/) {} // NOLINT +}; + +void except_constructor_NDC() +{ + static_assert(std::is_nothrow_copy_constructible<expected_sc<NDC>>::value, ""); + static_assert(std::is_nothrow_copy_assignable<expected_sc<NDC>>::value, ""); + static_assert(std::is_nothrow_move_constructible<expected_sc<NDC>>::value, ""); + static_assert(std::is_nothrow_move_assignable<expected_sc<NDC>>::value, ""); + expected_sc<NDC> e{1}; + BOOST_TEST(e.has_value()); +} + +void except_constructor_Date() +{ + static_assert(std::is_nothrow_move_constructible<expected_sc<Date>>::value, ""); + static_assert(std::is_nothrow_move_assignable<expected_sc<Date>>::value, ""); + expected_sc<Date> e{Date{1}}; + BOOST_TEST(e.has_value()); +} + +void except_constructor_TExcept() +{ + static_assert(!std::is_nothrow_move_constructible<expected_sc<TExcept>>::value, ""); + static_assert(!std::is_nothrow_move_assignable<expected_sc<TExcept>>::value, ""); + expected_sc<TExcept> e{TExcept{1}}; + BOOST_TEST(e.has_value()); +} + +void expected_from_in_place_value() +{ + OracleVal v; + expected_sc<Oracle> e{stde::in_place, v}; + // BOOST_REQUIRE_NO_THROW(e.value()); + BOOST_TEST(!!e); + BOOST_TEST(e.has_value()); + BOOST_TEST(bool(e)); + BOOST_TEST_EQ(e.value().s, sValueCopyConstructed); + BOOST_TEST_EQ(v.s, sValueConstructed); + + expected_sc<Oracle> e2{stde::in_place, std::move(v)}; // NOLINT + // BOOST_REQUIRE_NO_THROW(e2.value()); + BOOST_TEST(!!e2); + BOOST_TEST(e2.has_value()); + BOOST_TEST(bool(e2)); + BOOST_TEST_EQ(e2.value().s, sValueMoveConstructed); + BOOST_TEST_EQ(v.s, sMovedFrom); +} + +#if 0 +void expected_from_exception() +{ + // From stde::unexpected constructor. + stde::exception_or<int> e(stde::make_unexpected(test_exception())); + BOOST_TEST_THROWS(e.value(), test_exception); + BOOST_TEST_EQ(e.has_value(), false); + BOOST_TEST_EQ(static_cast<bool>(e), false); +} +#endif + +void expected_from_copy_value() +{ + // From copy constructor. + expected_sc<int> ef(5); + expected_sc<int> e(ef); + // BOOST_REQUIRE_NO_THROW(e.value()); + BOOST_TEST_EQ(e.value(), 5); + BOOST_TEST_EQ(*e, 5); + BOOST_TEST(e.has_value()); + BOOST_TEST(static_cast<bool>(e)); +} + +#if 0 +void expected_from_copy_exception() +{ + // From stde::unexpected constructor. + stde::exception_or<int> ef(stde::make_unexpected(test_exception())); + stde::exception_or<int> e(ef); + BOOST_TEST_THROWS(e.value(), test_exception); + BOOST_TEST_EQ(e.has_value(), false); + BOOST_TEST_EQ(static_cast<bool>(e), false); +} +#endif + +void expected_from_in_place() +{ + // From stde::in_place constructor. + expected_sc<std::string> e(stde::in_place, "stde::in_place"); + // BOOST_REQUIRE_NO_THROW(e.value()); + BOOST_TEST_EQ(e.value(), "stde::in_place"); + BOOST_TEST_EQ(*e, "stde::in_place"); + BOOST_TEST(e.has_value()); + BOOST_TEST(static_cast<bool>(e)); +} + +#if 0 +void expected_from_exception_ptr() +{ + // From exception_ptr constructor. + stde::exception_or<int> e(stde::make_unexpected(std::make_exception_ptr(test_exception()))); + BOOST_TEST_THROWS(e.value(), test_exception); + BOOST_TEST_EQ(e.has_value(), false); + BOOST_TEST_EQ(static_cast<bool>(e), false); +} +#endif + +void expected_from_moved_value() +{ + // From move value constructor. + std::string value = "my value"; + expected_sc<std::string> e = std::move(value); + // BOOST_REQUIRE_NO_THROW(e.value()); + BOOST_TEST_EQ(e.value(), "my value"); + BOOST_TEST_EQ(*e, "my value"); + BOOST_TEST(e.has_value()); + BOOST_TEST(static_cast<bool>(e)); +} + +void expected_from_catch_block() +{ + // From catch block + try + { + throw test_exception(); + } + catch(...) + { + stde::exception_or<int> e(stde::make_unexpected(std::current_exception())); + + BOOST_TEST_THROWS(e.value(), std::exception); + BOOST_TEST_EQ(e.has_value(), false); + BOOST_TEST_EQ(static_cast<bool>(e), false); + } +} + + +void make_expected_E_from_value() +{ + // auto e = stde::make_expected<std::string>( 5 ); + // BOOST_TEST_EQ(e.has_value(), false); +} +void make_expected_const_from_value() +{ +#if defined __clang__ && __clang_major__ >= 4 && __cplusplus > 201402L + const int i = 0; + auto e = expected_sc<const int>(i); + (void) e; +// static_assert(std::is_same<decltype(e), stde::success<const int>>::value, ""); +#endif +} +void make_expected_from_U_value() +{ + expected_sc<int> e = expected_sc<int>(short(5)); + static_assert(std::is_same<decltype(e), expected_sc<int>>{}, ""); + BOOST_TEST_EQ(e.has_value(), true); +} +void make_expected_from_U_value2() +{ + expected_sc<std::string> e = expected_sc<std::string>("aa"); + static_assert(std::is_same<decltype(e), expected_sc<std::string>>{}, ""); + BOOST_TEST_EQ(e.has_value(), true); +} + +void expected_from_value_error_condition() +{ + // From value constructor. + stde::expected<int, std::error_condition> e(5); + // BOOST_REQUIRE_NO_THROW(e.value()); + BOOST_TEST_EQ(e.value(), 5); + BOOST_TEST_EQ(*e, 5); + BOOST_TEST(e.has_value()); + BOOST_TEST(static_cast<bool>(e)); +} + +void expected_from_error_error_condition() +{ + // From stde::unexpected constructor. + stde::expected<int, std::error_condition> e(stde::make_unexpected<std::error_condition>(std::make_error_condition(std::errc::invalid_argument))); + auto error_from_except_check = [](const stde::bad_expected_access<std::error_condition> &except) { return std::errc(except.error().value()) == std::errc::invalid_argument; }; + try + { + (void) e.value(); + } + catch(stde::bad_expected_access<std::error_condition> &ex) + { + BOOST_TEST(error_from_except_check(ex)); + } + BOOST_TEST_EQ(e.has_value(), false); + BOOST_TEST_EQ(static_cast<bool>(e), false); +} + + +void expected_from_error_convertible() +{ + { + stde::expected<int, short> e1 = stde::make_unexpected<short>(1); + stde::expected<int, long> e2(e1); + BOOST_TEST_EQ(e2.has_value(), false); + BOOST_TEST_EQ(static_cast<bool>(e2), false); + BOOST_TEST_EQ(e2.error(), 1); + } + { + stde::expected<void, short> e1 = stde::make_unexpected<short>(1); + stde::expected<void, int> e2(e1); + BOOST_TEST_EQ(e2.has_value(), false); + BOOST_TEST_EQ(static_cast<bool>(e2), false); + BOOST_TEST_EQ(e2.error(), 1); + } +} + +void except_valid_constexpr_int() +{ + // From value constructor. + BOOST_CONSTEXPR stde::expected<int, long> e; + BOOST_CONSTEXPR bool b = e.has_value(); + BOOST_TEST(b); +} +void except_value_constexpr_int() +{ + // From value constructor. + BOOST_CONSTEXPR stde::expected<int, long> e(1); + BOOST_CONSTEXPR int x = e.value(); + BOOST_TEST_EQ(x, 1); +} + +void expected_from_value3() +{ + expected_sc<int> e(5); + BOOST_TEST_EQ(e.value(), 5); + + // From value assignment. + e = 8; + // BOOST_REQUIRE_NO_THROW(e.value()); + BOOST_TEST_EQ(e.value(), 8); + BOOST_TEST_EQ(*e, 8); + BOOST_TEST(e.has_value()); + BOOST_TEST(static_cast<bool>(e)); +} + +void expected_from_copy_expected() +{ + expected_sc<int> e(5); + expected_sc<int> e2(8); + + // From value assignment. + e = e2; + // BOOST_REQUIRE_NO_THROW(e.value()); + BOOST_TEST_EQ(e.value(), 8); + BOOST_TEST_EQ(*e, 8); + BOOST_TEST(e.has_value()); + BOOST_TEST(static_cast<bool>(e)); +} + +void expected_from_moved_expected() +{ + expected_sc<std::string> e("e"); + expected_sc<std::string> e2("e2"); + + // From value assignment. + e = std::move(e2); + // BOOST_REQUIRE_NO_THROW(e.value()); + BOOST_TEST_EQ(e.value(), "e2"); + BOOST_TEST_EQ(*e, "e2"); + BOOST_TEST(e.has_value()); + BOOST_TEST(static_cast<bool>(e)); + +// BOOST_REQUIRE_NO_THROW(e2.value()); +#ifndef __GLIBBOOST_OUTCOME_C__ + BOOST_TEST_EQ(e2.value(), ""); + BOOST_TEST_EQ(*e2, ""); +#endif + BOOST_TEST(e2.has_value()); + BOOST_TEST(static_cast<bool>(e2)); +} + +void expected_from_in_place2() +{ + // From stde::in_place constructor. + expected_sc<std::string> e(stde::in_place, "stde::in_place"); + BOOST_TEST_EQ(e.value(), "stde::in_place"); + + // From emplace method. + e.emplace("emplace method"); + // BOOST_REQUIRE_NO_THROW(e.value()); + BOOST_TEST_EQ(e.value(), "emplace method"); + BOOST_TEST_EQ(*e, "emplace method"); + BOOST_TEST(e.has_value()); + BOOST_TEST(static_cast<bool>(e)); +} + +void expected_from_move_value() +{ + expected_sc<std::string> e("v"); + + std::string value = "my value"; + // From assignment operator. + e = std::move(value); + // BOOST_REQUIRE_NO_THROW(e.value()); + BOOST_TEST_EQ(e.value(), "my value"); + BOOST_TEST_EQ(*e, "my value"); + BOOST_TEST(e.has_value()); + BOOST_TEST(static_cast<bool>(e)); +} + + +void expected_from_in_place3() +{ + // From stde::in_place factory. + // auto e = stde::make_expected<std::string>("stde::in_place"); + auto e = expected_sc<std::string>("stde::in_place"); + // BOOST_REQUIRE_NO_THROW(e.value()); + BOOST_TEST_EQ(e.value(), "stde::in_place"); + BOOST_TEST_EQ(*e, "stde::in_place"); + BOOST_TEST(e.has_value()); + BOOST_TEST(static_cast<bool>(e)); +} +void expected_from_in_place_error() +{ + // From stde::in_place factory. + auto e = stde::expected<std::string, std::error_condition>("stde::in_place"); + // BOOST_REQUIRE_NO_THROW(e.value()); + BOOST_TEST_EQ(e.value(), "stde::in_place"); + BOOST_TEST_EQ(*e, "stde::in_place"); + BOOST_TEST(e.has_value()); + BOOST_TEST(static_cast<bool>(e)); +} + +void expected_from_exception_catch() +{ + // From catch block + try + { + throw test_exception(); + } + catch(...) + { + stde::exception_or<int> e = stde::make_unexpected(std::current_exception()); + + BOOST_TEST_THROWS(e.value(), std::exception); + BOOST_TEST_EQ(e.has_value(), false); + BOOST_TEST_EQ(static_cast<bool>(e), false); + } +} + +#if 0 +void expected_from_error() +{ + // From stde::unexpected constructor. + auto e = stde::make_expected_from_error<int>(std::make_error_condition(std::errc::invalid_argument)); + auto error_from_except_check = [](const stde::bad_expected_access<std::error_condition> &except) { return std::errc(except.error().value()) == std::errc::invalid_argument; }; + try + { + (void) e.value(); + } + catch(stde::bad_expected_access<std::error_condition> &ex) + { + BOOST_TEST(error_from_except_check(ex)); + } + BOOST_TEST_EQ(e.has_value(), false); + BOOST_TEST_EQ(static_cast<bool>(e), false); +} + +void expected_from_error_U() +{ + // From stde::unexpected constructor. + auto e = stde::make_expected_from_error<int, short>(42); + static_assert(std::is_same<decltype(e), stde::expected<int, short>>{}, ""); + BOOST_TEST_EQ(e.has_value(), false); + BOOST_TEST_EQ(static_cast<bool>(e), false); +} + +void expected_from_exception2() +{ + // From stde::unexpected constructor. + auto e = stde::make_expected_from_exception<int>(test_exception()); + // auto e = expected_sc<int>(stde::unexpected<>(test_exception())); + BOOST_TEST_THROWS(e.value(), test_exception ); + BOOST_TEST_EQ(e.has_value(), false); + BOOST_TEST_EQ(static_cast<bool>(e), false); +} + +void expected_from_exception_ptr2() +{ + // From exception_ptr constructor. + auto e = stde::exception_or<int>(stde::make_unexpected(test_exception())); + BOOST_TEST_THROWS(e.value(), test_exception ); + BOOST_TEST_EQ(e.has_value(), false); + BOOST_TEST_EQ(static_cast<bool>(e), false); +} + +void make_expected_from_call_fun() +{ + try + { + stde::make_expected_from_call(throwing_fun); + BOOST_TEST(true); + } + catch(...) + { + BOOST_TEST(false); + } + stde::exception_or<int> e = stde::make_expected_from_call(throwing_fun); + BOOST_TEST_THROWS(e.value(), std::exception ); + BOOST_TEST_EQ(e.has_value(), false); + BOOST_TEST_EQ(static_cast<bool>(e), false); + + e = stde::make_expected_from_call(nothrowing_fun); + try + { + (void) e.value(); + BOOST_TEST(true); + } + catch(...) + { + BOOST_TEST(false); + } + BOOST_TEST_EQ(e.value(), 4); + BOOST_TEST_EQ(*e, 4); + BOOST_TEST_EQ(e.has_value(), true); + BOOST_TEST_EQ(static_cast<bool>(e), true); + +#if 0 + BOOST_TEST_THROWS(stde::make_expected_from_call<std::error_condition>(throwing_fun), test_exception); + + BOOST_TEST_NO_THROW(stde::make_expected_from_call<std::error_condition>(nothrowing_fun)); + stde::expected<int, std::error_condition> e2 = stde::make_expected_from_call<std::error_condition>(nothrowing_fun); + BOOST_TEST_NO_THROW(e2.value()); + BOOST_TEST_EQ(e2.value(), 4); + BOOST_TEST_EQ(*e2, 4); + BOOST_TEST_EQ(e2.has_value(), true); + BOOST_TEST_EQ(static_cast<bool>(e2), true); +#endif +} + +void make_expected_from_call_void_fun() +{ +#if 0 + BOOST_TEST_NO_THROW(stde::make_expected_from_call(void_throwing_fun)); + expected_sc<void> e = stde::make_expected_from_call(void_throwing_fun); + BOOST_TEST_THROWS(e.value(), std::exception); + BOOST_TEST_EQ(e.has_value(), false); + BOOST_TEST_EQ(static_cast<bool>(e), false); + + e = stde::make_expected_from_call(do_nothing_fun); + BOOST_TEST_NO_THROW(e.value()); + BOOST_TEST_EQ(e.has_value(), true); + BOOST_TEST_EQ(static_cast<bool>(e), true); + + BOOST_TEST_THROWS(stde::make_expected_from_call<std::error_condition>(void_throwing_fun), test_exception); + + try { + stde::make_expected_from_call<std::error_condition>(do_nothing_fun); + BOOST_TEST(true); + } + catch (...) + { + BOOST_TEST(false); + } + stde::expected<void, std::error_condition> e2 = stde::make_expected_from_call<std::error_condition>(do_nothing_fun); + try { + (void)e2.value(); + BOOST_TEST(true); + } + catch (...) + { + BOOST_TEST(false); + } + //BOOST_TEST_NO_THROW(e2.value()); + BOOST_TEST_EQ(e2.has_value(), true); + BOOST_TEST_EQ(static_cast<bool>(e2), true); +#endif +} +#endif + +void expected_swap_value() +{ + // From value constructor. + expected_sc<int> e(5); + expected_sc<int> e2(8); + + e.swap(e2); + + BOOST_TEST_EQ(e.value(), 8); + BOOST_TEST_EQ(e2.value(), 5); + + e2.swap(e); + + BOOST_TEST_EQ(e.value(), 5); + BOOST_TEST_EQ(e2.value(), 8); +} + +#if 0 +void expected_swap_exception() +{ + // From value constructor. + stde::exception_or<int> e = stde::make_unexpected(std::invalid_argument("e")); + stde::exception_or<int> e2 = stde::make_unexpected(std::invalid_argument("e2")); + + e.swap(e2); + + auto equal_to_e = [](const std::invalid_argument &except) { return std::string(except.what()) == "e"; }; + auto equal_to_e2 = [](const std::invalid_argument &except) { return std::string(except.what()) == "e2"; }; + + try + { + (void) e.value(); + BOOST_TEST(true); + } + catch(std::invalid_argument &ex) + { + BOOST_TEST(equal_to_e2(ex)); + } + try + { + (void) e2.value(); + BOOST_TEST(true); + } + catch(std::invalid_argument &ex) + { + BOOST_TEST(equal_to_e(ex)); + } + + e2.swap(e); + + try + { + (void) e.value(); + BOOST_TEST(true); + } + catch(std::invalid_argument &ex) + { + BOOST_TEST(equal_to_e(ex)); + } + try + { + (void) e2.value(); + BOOST_TEST(true); + } + catch(std::invalid_argument &ex) + { + BOOST_TEST(equal_to_e2(ex)); + } +} +#endif + +void expected_swap_function_value() +{ + // From value constructor. + expected_sc<int> e(5); + expected_sc<int> e2(8); + + swap(e, e2); + + BOOST_TEST_EQ(e.value(), 8); + BOOST_TEST_EQ(e2.value(), 5); + + swap(e, e2); + + BOOST_TEST_EQ(e.value(), 5); + BOOST_TEST_EQ(e2.value(), 8); +} + + +#ifdef QUICKCPPLIB_BOOST_UNIT_TEST_HPP +int main() +#else +BOOST_AUTO_TEST_CASE(expected_pass) +#endif +{ + + static_assert(!std::is_default_constructible<NoDefaultConstructible>::value, ""); + static_assert(!std::is_default_constructible<expected_sc<NoDefaultConstructible>>::value, ""); + + static_assert(!std::is_copy_constructible<NoCopyConstructible>::value, ""); + static_assert(!std::is_constructible<expected_sc<NoCopyConstructible>, NoCopyConstructible const &>::value, ""); + static_assert(!std::is_constructible<stde::exception_or<NoCopyConstructible>, stde::exception_or<NoCopyConstructible> const &>::value, ""); + static_assert(!std::is_copy_constructible<stde::exception_or<NoCopyConstructible>>::value, ""); + +#if 0 + // fixme + { + NoMoveConstructible nmc; + // NoMoveConstructible nmc2 = std::move(nmc); // FAILS as expected + + expected_sc<NoMoveConstructible> x{std::move(nmc)}; // DOESN'T FAIL as copy is selected instead + (void) x; + } +// fixme +#if defined __clang__ && __clang_major__ >= 4 && __cplusplus > 201402L + { + NoMoveConstructible nmc; + // NoMoveConstructible nmc2 = std::move(nmc); // FAILS as expected + + expected_sc<NoMoveConstructible> x = std::move(nmc); // DOESN'T FAIL as copy is selected instead + (void) x; + } +#endif +#endif + + static_assert(!std::is_move_constructible<NoMoveConstructible>::value, ""); + static_assert(!std::is_constructible<expected_sc<NoMoveConstructible>, NoMoveConstructible &&>::value, ""); + static_assert(std::is_move_constructible<expected_sc<NoMoveConstructible>>::value, ""); + + except_default_constructor(); + except_default_constructor_error_code(); + except_default_constructor_constexpr(); + expected_from_value(); + expected_from_value2(); + expected_from_cnv_value(); + except_constructor_NDCE(); + except_constructor_NDC(); + except_constructor_Date(); + expected_from_in_place_value(); + // expected_from_exception(); + expected_from_copy_value(); + // expected_from_copy_exception(); + expected_from_in_place(); + // expected_from_exception_ptr(); + expected_from_moved_value(); + expected_from_catch_block(); + make_expected_E_from_value(); + make_expected_const_from_value(); + make_expected_from_U_value2(); + expected_from_value_error_condition(); + expected_from_error_error_condition(); + expected_from_error_convertible(); + except_valid_constexpr_int(); + except_value_constexpr_int(); + expected_from_value3(); + expected_from_copy_expected(); + expected_from_moved_expected(); + expected_from_in_place2(); + expected_from_move_value(); + expected_from_in_place3(); + expected_from_in_place_error(); + expected_from_exception_catch(); + // expected_from_error(); + // expected_from_error_U(); + // expected_from_exception2(); + // expected_from_exception_ptr2(); + // make_expected_from_call_fun(); + // make_expected_from_call_void_fun(); + expected_swap_value(); + // expected_swap_exception(); + expected_swap_function_value(); + +#ifdef QUICKCPPLIB_BOOST_UNIT_TEST_HPP + return QUICKCPPLIB_NAMESPACE::unit_test::current_test_case()->fails != 0; +#endif +} + +#if 0 +/////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// + + +//void expected_from_error_catch_exception) +//{ +// // From catch block +// try +// { +// throw test_exception(); +// } +// catch(...) +// { +// auto throw_lambda = [](){ return stde::make_expected_from_error<int,std::error_condition>();}; +// +// //BOOST_TEST_THROWS(throw_lambda(), test_exception); +// } +//} + + + +//////////////////////////////////// +BOOST_AUTO_TEST_SUITE(expected_map) + +void expected_map() +{ + auto fun = [](bool b) -> expected_sc<int> + { + if (b) + return stde::make_expected(5); + else + return stde::make_unexpected(test_exception()); + }; + + auto add_five = [](int sum) -> int + { + return sum + 5; + }; + + auto launch_except = [](int sum) -> int + { + throw test_exception(); + }; + + expected_sc<int> e = fun(true).map(add_five); + BOOST_TEST_NO_THROW(e.value()); + BOOST_TEST_EQ(*e, 10); + + e = fun(true).map(add_five).map(add_five); + BOOST_TEST_NO_THROW(e.value()); + BOOST_TEST_EQ(*e, 15); + + e = fun(false).map(add_five).map(add_five); + BOOST_TEST_THROWS(e.value(), test_exception); + + BOOST_TEST_THROWS(fun(true).map(launch_except), test_exception); + +} + +void expected_void_map() +{ + auto fun = [](bool b) + { + if (b) + return stde::make_expected(); + else + return expected_sc<void>(stde::make_unexpected(test_exception())); + }; + + auto launch_except = []() -> void + { + throw test_exception(); + }; + + auto do_nothing = []() {}; + + expected_sc<void> e = fun(true).map(do_nothing); + BOOST_TEST_NO_THROW(e.value()); + + e = fun(false).map(do_nothing); + BOOST_TEST_THROWS(e.value(), test_exception); + + BOOST_TEST_THROWS(fun(true).map(launch_except), test_exception); + +} + +BOOST_AUTO_TEST_SUITE_END() + +//////////////////////////////////// +BOOST_AUTO_TEST_SUITE(expected_bind) + +void expected_bind() +{ + auto fun = [](bool b) -> expected_sc<int> + { + if (b) + return stde::make_expected(5); + else + return stde::make_unexpected(test_exception()); + }; + + auto add_five = [](int sum) -> expected_sc<int> + { + return stde::make_expected(sum + 5); + }; + + auto launch_except = [](int sum) -> expected_sc<int> + { + throw test_exception(); + }; + + expected_sc<int> e = fun(true).bind(add_five); + BOOST_TEST_NO_THROW(e.value()); + BOOST_TEST_EQ(*e, 10); + + e = fun(true).bind(add_five).bind(add_five); + BOOST_TEST_NO_THROW(e.value()); + BOOST_TEST_EQ(*e, 15); + + e = fun(false).bind(add_five).bind(add_five); + BOOST_TEST_THROWS(e.value(), test_exception); + + BOOST_TEST_THROWS(fun(true).bind(launch_except), test_exception); + +} + +void expected_void_bind() +{ + auto fun = [](bool b) + { + if (b) + return stde::make_expected(); + else + return expected_sc<void>(stde::make_unexpected(test_exception())); + }; + + auto launch_except = []() -> expected_sc<void> + { + throw test_exception(); + }; + + auto do_nothing = []() { + return stde::make_expected(); + }; + + expected_sc<void> e = fun(true).bind(do_nothing); + BOOST_TEST_NO_THROW(e.value()); + + e = fun(false).bind(do_nothing); + BOOST_TEST_THROWS(e.value(), test_exception); + + BOOST_TEST_THROWS(fun(true).bind(launch_except), test_exception); + +} + +BOOST_AUTO_TEST_SUITE_END() + + +//////////////////////////////////// +BOOST_AUTO_TEST_SUITE(expected_then) + +void expected_non_void_then() +{ + auto fun = [](bool b) -> expected_sc<int> + { + if (b) + return stde::make_expected(5); + else + return stde::make_unexpected(test_exception()); + }; + + + auto add_five = [](int sum) -> int + { + return sum + 5; + }; + auto six = []() -> int + { + return 6; + }; + + auto pair = [](int a) -> bool + { + return (a % 2) == 0; + }; + + auto launch_except = [](int sum) -> int + { + throw test_exception(); + }; + + auto then_launch_except = [](expected<int>) -> int + { + throw test_exception(); + }; + + expected_sc<int> e = fun(true).then(if_valued(add_five)); + BOOST_TEST_NO_THROW(e.value()); + BOOST_TEST_EQ(*e, 10); + + e = fun(true).then(if_valued(ident(six))); + BOOST_TEST_NO_THROW(e.value()); + BOOST_TEST_EQ(*e, 6); + + e = fun(false).then(if_unexpected(ident(six))); + BOOST_TEST_NO_THROW(e.value()); + BOOST_TEST_EQ(*e, 6); + + expected_sc<bool> e1 = fun(true).then(if_valued(pair)); + BOOST_TEST_NO_THROW(e1.value()); + BOOST_TEST_EQ(*e1, false); + + + + e = fun(true).then(if_valued(add_five)).then(if_valued(add_five)); + BOOST_TEST_NO_THROW(e.value()); + BOOST_TEST_EQ(*e, 15); + + e = fun(false).then(if_valued(add_five)).then(if_valued(add_five)); + BOOST_TEST_THROWS(e.value(), test_exception); + + BOOST_TEST_THROWS(fun(true).then(if_valued(launch_except)), test_exception); + + e = fun(false).then(catch_all(then_launch_except)); + BOOST_TEST_THROWS(e.value(), test_exception); + +} + +void expected_void_then() +{ + auto fun = [](bool b) -> expected_sc<void> + { + if (b) + return stde::make_expected(); + else + return stde::make_unexpected(test_exception()); + }; + + auto launch_except = []() + { + throw test_exception(); + }; + + auto do_nothing = []() {}; + + BOOST_TEST(true); + expected_sc<void> e = fun(true).then(if_valued(do_nothing)); + BOOST_TEST_NO_THROW(e.value()); + + e = fun(false).then(if_valued(do_nothing)); + BOOST_TEST_THROWS(e.value(), test_exception); + + BOOST_TEST_THROWS(fun(true).then(if_valued(launch_except)), test_exception); + +} + +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(expected_recover) + +void expected_recover() +{ + auto fun = [](bool b) + { + if (b) + return expected_sc<int>(5); + else + return expected_sc<int>(stde::make_unexpected(test_exception())); + }; + + auto add_five = [](int sum) -> expected_sc<int> + { + return stde::make_expected(sum + 5); + }; + + auto recover_error = [](std::exception_ptr p) + { + return stde::make_expected(0); + }; + + auto recover_error_silent_failure = [](std::exception_ptr p) + { + return expected_sc<int>(stde::make_unexpected(p)); + }; + + auto recover_error_failure = [](std::exception_ptr p) -> expected_sc<int> + { + return expected_sc<int>(stde::make_unexpected(test_exception())); + }; + + auto recover_error_throws = [](std::exception_ptr p) -> expected_sc<int> + { + throw test_exception(); + }; + + BOOST_TEST_EQ(fun(false).catch_error(recover_error).has_value(), true); + BOOST_TEST_EQ(fun(false).catch_error(recover_error).value(), 0); + BOOST_TEST_EQ(fun(true).catch_error(recover_error).value(), 5); + BOOST_TEST_EQ(fun(false).catch_error(recover_error_silent_failure).has_value(), false); + BOOST_TEST_EQ(fun(false).catch_error(recover_error_failure).has_value(), false); + + BOOST_TEST_EQ(fun(true).bind(add_five).value(), 10); + BOOST_TEST_EQ(fun(true).bind(add_five).catch_error(recover_error).value(), 10); + BOOST_TEST_EQ(fun(true).bind(add_five).catch_error(recover_error_silent_failure).value(), 10); + BOOST_TEST_EQ(fun(true).bind(add_five).catch_error(recover_error_failure).value(), 10); + + BOOST_TEST_EQ(fun(false).catch_error(recover_error).bind(add_five).value(), 5); + BOOST_TEST_EQ(fun(false).catch_error(recover_error).bind(add_five).bind(add_five).value(), 10); + BOOST_TEST_EQ(fun(false).catch_error(recover_error_failure).bind(add_five).has_value(), false); + BOOST_TEST_EQ(fun(false).bind(add_five).catch_error(recover_error_failure).bind(add_five).has_value(), false); + BOOST_TEST_EQ(fun(false).bind(add_five).catch_error(recover_error_silent_failure).bind(add_five).has_value(), false); + + BOOST_TEST_THROWS(fun(false).catch_error(recover_error_throws), test_exception); + +} + +void expected_void_recover() +{ + auto fun = [](bool b) + { + if (b) + return stde::make_expected(); + else + return expected_sc<void>(boost::stde::make_unexpected(test_exception())); + }; + + auto do_nothing = []() { + return stde::make_expected(); + }; + + auto recover_error = [](std::exception_ptr p) + { + return stde::make_expected(); + }; + + auto recover_error_silent_failure = [](std::exception_ptr p) + { + return expected_sc<void>(boost::stde::make_unexpected(p)); + }; + + auto recover_error_failure = [](std::exception_ptr p) -> expected_sc<void> + { + throw test_exception(); + }; + + // The catch_error doesn't alter the stde::expected if it's valid. + BOOST_TEST_EQ(fun(true).catch_error(recover_error_failure).has_value(), true); + + // Simple catch_error tests. + BOOST_TEST_EQ(fun(false).catch_error(recover_error).has_value(), true); + BOOST_TEST_THROWS(fun(false).catch_error(recover_error_failure), test_exception); + BOOST_TEST_EQ(fun(false).catch_error(recover_error_silent_failure).has_value(), false); + + // With a bind between. + BOOST_TEST_THROWS(fun(false).bind(do_nothing).catch_error(recover_error_failure), test_exception); + +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(proposal) + +void proposal_concept() +{ + using namespace std; + + { + stde::expected<int, string> ei = 0; + stde::expected<int, string> ej = 1; + stde::expected<int, string> ek = stde::make_unexpected(string()); + + ei = 1; + ej = stde::make_unexpected(string());; + ek = 0; + + ei = stde::make_unexpected(string());; + ej = 0; + ek = 1; + } +} +void proposal_init() +{ + using namespace std; + { + string s{ "STR" }; + + stde::expected<string, int> ep{ stde::make_unexpected(-1) }; // unexpected value, requires Movable<E> + stde::expected<string, int> eq = { stde::make_unexpected(-1) }; // unexpected value, requires Movable<E> + + expected_sc<string> es{ s }; // requires Copyable<T> + expected_sc<string> et = s; // requires Copyable<T> + expected_sc<string> ev = string{ "STR" }; // requires Movable<T> + + expected_sc<string> ew; // unexpected value + expected_sc<string> ex{}; // unexpected value + expected_sc<string> ey = {}; // unexpected value + expected_sc<string> ez = expected_sc<string>{}; // unexpected value + } + + { + stde::expected<Guard, int> eg; // unexpected value + stde::expected<Guard, int> eh{}; // unexpected value + stde::expected<Guard, int> ei{ stde::in_place }; // calls Guard{} in place + stde::expected<Guard, int> ej{ stde::in_place, "arg" }; // calls Guard{"arg"} in place + } + + { + stde::expected<int, string> ei{ unexpect }; // unexpected value, calls string{} in place + stde::expected<int, string> ej{ unexpect, "arg" }; // unexpected value, calls string{"arg"} in place + } +} +void proposal_make_unexpected_fact() +{ + using namespace std; + { + stde::expected<string, int> opt1 = stde::make_unexpected(1); + stde::expected<string, int> opt2 = { unexpect, 1 }; + + opt1 = stde::make_unexpected(1); + opt2 = { unexpect, 1 }; + } +} +void proposal_error_exception_ts() +{ + using namespace std; + { + stde::expected<int, error_exception<std::error_code, std::system_error> > e = + stde::make_unexpected(make_error_code(errc::invalid_argument)); +#if !defined BOOST_MSVC || BOOST_MSVC >= 1900 + BOOST_TEST(e.error() == make_error_code(errc::invalid_argument)); +#else + // VS2013 doesn't match operator==(boost::error_exception<std::error_code,std::system_error>, std::error_code) + BOOST_TEST(e.error() == (error_exception<std::error_code, std::system_error>(make_error_code(errc::invalid_argument)))); +#endif + try { + e.value(); + BOOST_TEST(false); + } + catch (std::system_error const& ex) { + + } + catch (...) { + BOOST_TEST(false); + } + stde::expected<int, error_exception<std::error_code, std::system_error> > e2 = stde::make_unexpected(e.error()); +#if !defined BOOST_MSVC || BOOST_MSVC >= 1900 + BOOST_TEST(e2.error() == make_error_code(errc::invalid_argument)); +#else + // VS2013 doesn't match operator==(boost::error_exception<std::error_code,std::system_error>, std::error_code) + BOOST_TEST(e2.error() == (error_exception<std::error_code, std::system_error>(make_error_code(errc::invalid_argument)))); +#endif + try { + e2.value(); + BOOST_TEST(false); + } + catch (std::system_error const& ex) { + + } + catch (...) { + BOOST_TEST(false); + } + + } +} +void proposal_ensured_read_ts() +{ + using namespace std; + { + ensured_read<int> e = make_ensured_read(1); + BOOST_TEST(e == 1); + } + { + ensured_read<int> e = make_ensured_read(1); + stde::unexpected<ensured_read<int>> ue1 = stde::make_unexpected(std::move(e)); + BOOST_TEST(ue1.value() == 1); + } + // { + // stde::make_unexpected(make_ensured_read(1)); + // // calls to terminate. + // } + // { + // stde::expected<int, ensured_read<int> > e = stde::make_unexpected(make_ensured_read(1)); + // // calls to terminate. + // } + { + stde::expected<int, ensured_read<int> > e{ 1 }; + BOOST_TEST(e.value() == 1); + } + { + stde::expected<int, ensured_read<int> > e = stde::make_unexpected(make_ensured_read(1)); + BOOST_TEST(e.error() == 1); + } + { + stde::expected<int, ensured_read<int> > e{ unexpect, 1 }; + BOOST_TEST(e.error() == 1); + } + { + ensured_read<std::exception_ptr> e = make_ensured_read(std::make_exception_ptr(1)); + BOOST_TEST_THROWS(std::rethrow_exception(e.value()), int); + } + { + stde::expected<int, ensured_read<std::exception_ptr> > e = stde::make_unexpected(make_ensured_read(std::make_exception_ptr(1))); + BOOST_TEST_THROWS(std::rethrow_exception(e.error().value()), int); + } +} +void proposal_relational_operators() +{ + using namespace std; + { + stde::expected<unsigned, int> e0{ 0 }; + stde::expected<unsigned, int> e1{ 1 }; + stde::expected<unsigned, int> eN{ unexpect, -1 }; + + BOOST_TEST(eN < e0); + BOOST_TEST(e0 < e1); + BOOST_TEST(!(e0 < eN)); + BOOST_TEST(eN <= e0); + BOOST_TEST(e0 <= e1); + + BOOST_TEST(e0 > eN); + BOOST_TEST(e1 > e0); + BOOST_TEST(e0 >= eN); + BOOST_TEST(e1 >= e0); + + BOOST_TEST(!(eN < eN)); + BOOST_TEST(!(e1 < e1)); + BOOST_TEST(eN <= eN); + BOOST_TEST(e1 <= e1); + + BOOST_TEST(eN != e0); + BOOST_TEST(e0 != e1); + BOOST_TEST(eN == eN); + BOOST_TEST(e0 == e0); + + ////// + + BOOST_TEST(eN == stde::make_unexpected(-1)); + BOOST_TEST(e0 != stde::make_unexpected(1)); + BOOST_TEST(eN != 1u); + BOOST_TEST(e1 == 1u); + + BOOST_TEST(eN < 1u); + BOOST_TEST(eN <= 1u); + BOOST_TEST(1u > eN); + BOOST_TEST(!(1u < eN)); + BOOST_TEST(1u >= eN); + BOOST_TEST(stde::make_unexpected(1) < e0); + BOOST_TEST(stde::make_unexpected(1) <= e0); + BOOST_TEST(!(stde::make_unexpected(1) > e0)); + BOOST_TEST(!(stde::make_unexpected(1) >= e0)); + + + BOOST_TEST(!(e0 < stde::make_unexpected(1))); + BOOST_TEST(!(e0 <= stde::make_unexpected(1))); + BOOST_TEST(e0 > stde::make_unexpected(1)); + BOOST_TEST(e0 >= stde::make_unexpected(1)); + } + { + stde::expected<void, int> e0{ boost::expect }; + stde::expected<void, int> eN{ unexpect, -1 }; + + BOOST_TEST(!(e0 < e0)); + BOOST_TEST(eN < e0); + BOOST_TEST(!(e0 < eN)); + BOOST_TEST(!(eN < eN)); + BOOST_TEST(e0 <= e0); + BOOST_TEST(eN <= e0); + BOOST_TEST(!(e0 <= eN)); + BOOST_TEST(eN <= eN); + + BOOST_TEST(!(e0 > e0)); + BOOST_TEST(e0 > eN); + BOOST_TEST(!(eN > e0)); + BOOST_TEST(!(eN > eN)); + BOOST_TEST(e0 >= e0); + BOOST_TEST(e0 >= eN); + BOOST_TEST(!(eN >= e0)); + BOOST_TEST(eN >= eN); + + BOOST_TEST(!(e0 != e0)); + BOOST_TEST(eN != e0); + BOOST_TEST(e0 != eN); + BOOST_TEST(!(eN != eN)); + BOOST_TEST(e0 == e0); + BOOST_TEST(!(eN == e0)); + BOOST_TEST(!(e0 == eN)); + BOOST_TEST(eN == eN); + + ////// + + BOOST_TEST(eN == stde::make_unexpected(-1)); + BOOST_TEST(e0 != stde::make_unexpected(1)); + + BOOST_TEST(stde::make_unexpected(1) < e0); + BOOST_TEST(stde::make_unexpected(1) <= e0); + BOOST_TEST(!(stde::make_unexpected(1) > e0)); + BOOST_TEST(!(stde::make_unexpected(1) >= e0)); + + BOOST_TEST(!(stde::make_unexpected(1) < eN)); + BOOST_TEST(!(stde::make_unexpected(1) <= eN)); + BOOST_TEST(stde::make_unexpected(1) > eN); + BOOST_TEST(stde::make_unexpected(1) >= eN); + + BOOST_TEST(!(eN < stde::make_unexpected(-1))); + BOOST_TEST(eN <= stde::make_unexpected(-1)); + BOOST_TEST(!(eN > stde::make_unexpected(-1))); + BOOST_TEST(eN >= stde::make_unexpected(-1)); + } +} +void proposal_dereference_operators() +{ + using namespace std; + { + const string s{ "STR" }; + + expected_sc<string> e0{ s }; + const expected_sc<string> e1{ s }; + BOOST_TEST(*e0.operator->() == s); + BOOST_TEST(*e1.operator->() == s); + + // Test with class which has operator&() overloaded + const OverloadedAddressOf o{}; + BOOST_TEST(&o == nullptr); + + expected_sc<OverloadedAddressOf> e2{ o }; + const expected_sc<OverloadedAddressOf> e3{ o }; + BOOST_TEST(e2.operator->() != nullptr); + BOOST_TEST(e3.operator->() != nullptr); + } +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(movesem) +////////////////////////////// +void movesem_moved_from_state() +{ + // first, test mock: + MoveAware<int> i{ 1 }, j{ 2 }; + BOOST_TEST(i.val == 1); + BOOST_TEST(!i.moved); + BOOST_TEST(j.val == 2); + BOOST_TEST(!j.moved); + + MoveAware<int> k = std::move(i); + BOOST_TEST(k.val == 1); + BOOST_TEST(!k.moved); + BOOST_TEST(i.val == 1); + BOOST_TEST(i.moved); + + k = std::move(j); + BOOST_TEST(k.val == 2); + BOOST_TEST(!k.moved); + BOOST_TEST(j.val == 2); + BOOST_TEST(j.moved); + + // now, test stde::expected + expected_sc<MoveAware<int>> oi{ 1 }, oj{ 2 }; + BOOST_TEST(oi); + BOOST_TEST(!oi->moved); + BOOST_TEST(oj); + BOOST_TEST(!oj->moved); + + expected_sc<MoveAware<int>> ok{ std::move(oi) }; + BOOST_TEST(ok); + BOOST_TEST(!ok->moved); + BOOST_TEST(oi); + BOOST_TEST(oi->moved); + + ok = std::move(oj); + BOOST_TEST(ok); + BOOST_TEST(!ok->moved); + BOOST_TEST(oj); + BOOST_TEST(oj->moved); + +} +void movesem_move_only_value() +{ + const auto make_int = []() { + std::unique_ptr<int> value{ new int }; + *value = 100; + return value; + }; + const auto return_void = [](std::unique_ptr<int> value) { + BOOST_TEST(value != nullptr); + BOOST_TEST(*value == 100); + }; + const auto return_expected = [](std::unique_ptr<int> value) { + BOOST_TEST(value != nullptr); + BOOST_TEST(*value == 100); + return expected_sc<void>{boost::expect}; + }; + const auto return_int = [](std::unique_ptr<int> value) { + BOOST_TEST(value != nullptr); + BOOST_TEST(*value == 100); + return 200; + }; + + BOOST_TEST(expected<std::unique_ptr<int>>{make_int()}.map(return_void)); + BOOST_TEST(expected<std::unique_ptr<int>>{make_int()}.map(return_expected)); + BOOST_TEST(expected<std::unique_ptr<int>>{make_int()}.map(return_int)); +} +void movesem_move_only_value2() +{ + const auto make_int = []() { + std::unique_ptr<int> value{ new int }; + *value = 100; + return value; + }; + const auto return_expected_void = [](std::unique_ptr<int> value) { + BOOST_TEST(value != nullptr); + BOOST_TEST(*value == 100); + return stde::make_expected(); + }; + const auto return_expected = [](std::unique_ptr<int> value) { + BOOST_TEST(value != nullptr); + BOOST_TEST(*value == 100); + return expected_sc<void>{boost::expect}; + }; + BOOST_TEST(expected<std::unique_ptr<int>>{make_int()}.bind(return_expected_void)); + BOOST_TEST(expected<std::unique_ptr<int>>{make_int()}.bind(return_expected)); +} +void movesem_copy_move_ctor_optional_int() +{ + expected_sc<int> oi; + expected_sc<int> oj = oi; + + BOOST_TEST(oj); + BOOST_TEST(oj == oi); + BOOST_TEST(bool(oj)); + + oi = 1; + expected_sc<int> ok = oi; + BOOST_TEST(!!ok); + BOOST_TEST(bool(ok)); + BOOST_TEST(ok == oi); + BOOST_TEST(ok != oj); + BOOST_TEST(*ok == 1); + + expected_sc<int> ol = std::move(oi); + BOOST_TEST(!!ol); + BOOST_TEST(bool(ol)); + BOOST_TEST(ol == oi); + BOOST_TEST(ol != oj); + BOOST_TEST(*ol == 1); +} +void movesem_expected_expected() +{ + expected_sc<stde::expected<int, int>> oi1 = stde::make_unexpected(-1); + BOOST_TEST(!oi1); + + { + expected_sc<expected_sc<int>> oi2{ stde::expect }; + BOOST_TEST(bool(oi2)); + BOOST_TEST((*oi2)); + //std::cout << typeid(**oi2).name() << std::endl; + } + + { + expected_sc<stde::expected<int, int>> oi2{ stde::expect, stde::make_unexpected(-1) }; + BOOST_TEST(bool(oi2)); + BOOST_TEST(!*oi2); + } + + { + stde::expected<stde::expected<int>> oi2{ stde::expected<int>{} }; + BOOST_TEST(bool(oi2)); + BOOST_TEST(*oi2); + } + + stde::expected<int> oi; + auto ooi = stde::make_expected(oi); + static_assert(std::is_same<expected<expected<int>>, decltype(ooi)>::value, ""); + +} +BOOST_AUTO_TEST_SUITE_END() + +void process() {} +void process(int) {} +void processNil() {} + +BOOST_AUTO_TEST_SUITE(Examples) +////////////////////////////// + +void example1() +{ + stde::expected<int> oi; // create disengaged object + stde::expected<int> oj = { unexpect }; // alternative syntax + oi = oj; // assign disengaged object + stde::expected<int> ok = oj; // ok is disengaged + + if (oi) BOOST_TEST(false); // 'if oi is engaged...' + if (!oi) BOOST_TEST(true); // 'if oi is disengaged...' + + BOOST_TEST(oi == ok); // two disengaged optionals compare equal + + /////////////////////////////////////////////////////////////////////////// + stde::expected<int> ol{ 1 }; // ol is engaged; its contained value is 1 + ok = 2; // ok becomes engaged; its contained value is 2 + oj = ol; // oj becomes engaged; its contained value is 1 + + BOOST_TEST(oi != ol); // disengaged != engaged + BOOST_TEST(ok != ol); // different contained values + BOOST_TEST(oj == ol); // same contained value + //BOOST_TEST(oi < ol); // disengaged < engaged + //BOOST_TEST(ol < ok); // less by contained value + + ///////////////////////////////////////////////////////////////////////////// + stde::expected<int> om{ 1 }; // om is engaged; its contained value is 1 + stde::expected<int> on = om; // on is engaged; its contained value is 1 + om = 2; // om is engaged; its contained value is 2 + BOOST_TEST(on != om); // on still contains 3. They are not pointers + + ///////////////////////////////////////////////////////////////////////////// + int i = *ol; // i obtains the value contained in ol + BOOST_TEST(i == 1); + *ol = 9; // the object contained in ol becomes 9 + BOOST_TEST(*ol == 9); + BOOST_TEST(ol == stde::make_expected(9)); + + /////////////////////////////////// + int p = 1; + stde::expected<int> op = p; + BOOST_TEST(*op == 1); + p = 2; + BOOST_TEST(*op == 1); // value contained in op is separated from p + + //////////////////////////////// + if (ol) + process(*ol); // use contained value if present + else + process(); // proceed without contained value + + if (!om) + processNil(); + else + process(*om); + + ///////////////////////////////////////// + process(ol.value_or(0)); // use 0 if ol is disengaged + + //////////////////////////////////////////// + ok = { unexpect }; // if ok was engaged calls T's dtor + oj = {}; // assigns a temporary disengaged stde::expected +} +////////////////////////////////////////////////// +void ValueOr() +{ + stde::expected<int> oi = 1; + int i = oi.value_or(0); + BOOST_TEST(i == 1); + + oi = { unexpect }; + BOOST_TEST(oi.value_or(3) == 3); + + stde::expected<std::string> os{ "AAA" }; + BOOST_TEST(os.value_or("BBB") == "AAA"); + os = {}; + BOOST_TEST(os); + BOOST_TEST(os.value() == ""); + + BOOST_TEST(os.value_or(std::string("BBB")) == ""); + { + constexpr stde::expected<int> e = 1; + static_assert(e.has_value(), ""); + static_assert(*e == 1, ""); + static_assert(e.value() == 1, ""); + } + { + constexpr std::error_code ec = std::make_error_code(std::errc(1)); + constexpr stde::expected<int> e = stde::make_unexpected(ec); + static_assert(!e.has_value(), ""); + static_assert(e.error() == ec, ""); + } + { + constexpr stde::expected<OracleVal> e = 1; + static_assert(e.has_value(), ""); + static_assert(*e == 1, ""); + static_assert(e.value() == 1, ""); + } + { + constexpr std::error_code ec = std::make_error_code(std::errc(1)); + constexpr stde::expected<OracleVal> e = stde::make_unexpected(ec); + static_assert(!e.has_value(), ""); + static_assert(e.error() == ec, ""); + } +} + +////////////////////////////////////////////////// +BOOST_AUTO_TEST_SUITE_END() + +#endif + +#else +int main(void) +{ + return 0; +} +#endif diff --git a/src/boost/libs/outcome/test/tests/comparison.cpp b/src/boost/libs/outcome/test/tests/comparison.cpp new file mode 100644 index 000000000..1c093ffd2 --- /dev/null +++ b/src/boost/libs/outcome/test/tests/comparison.cpp @@ -0,0 +1,102 @@ +/* Unit testing for outcomes +(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (6 commits) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#ifdef _MSC_VER +#pragma warning(disable : 4127) // conditional expression is constant +#pragma warning(disable : 4244) // conversion from int to short +#endif + +#include <boost/outcome/outcome.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +BOOST_OUTCOME_AUTO_TEST_CASE(works_outcome_comparison, "Tests that the outcome can compare to compatible outcomes") +{ +#if !defined(__APPLE__) || defined(__cpp_exceptions) + using namespace BOOST_OUTCOME_V2_NAMESPACE; + auto p = boost::copy_exception(std::runtime_error("hi")); + // value comparison + { + outcome<int> a(1), b(2), c(2); + BOOST_CHECK(a == a); + BOOST_CHECK(b == b); + BOOST_CHECK(c == c); + BOOST_CHECK(a != b); + BOOST_CHECK(b == c); + } + // homogeneous outcome comparison + { + outcome<int> a(1), b(2), c(boost::system::errc::invalid_argument), d(p); + BOOST_CHECK(a == a); + BOOST_CHECK(a != b); + BOOST_CHECK(a != c); + BOOST_CHECK(a != d); + BOOST_CHECK(b == b); + BOOST_CHECK(b != c); + BOOST_CHECK(b != d); + BOOST_CHECK(c == c); + BOOST_CHECK(c != d); + BOOST_CHECK(d == d); + outcome<int> e(boost::system::errc::invalid_argument), f(p); + BOOST_CHECK(c == e); + BOOST_CHECK(d == f); + } + // heterogeneous outcome comparison, so outcome<int> to outcome<double> etc + { + outcome<int> a(1); + outcome<double> b(1); + outcome<unsigned short> c(1); + BOOST_CHECK(a == b); + BOOST_CHECK(a == c); + BOOST_CHECK(b == a); + BOOST_CHECK(b == c); + BOOST_CHECK(c == a); + BOOST_CHECK(c == b); + // outcome<void> e(in_place_type<void>); + outcome<unsigned short> f(boost::system::errc::invalid_argument); + outcome<double> g(p); + // BOOST_CHECK(a != e); + BOOST_CHECK(a != f); + BOOST_CHECK(a != g); + // BOOST_CHECK(e != f); + BOOST_CHECK(f != g); + } + // upconverting outcome comparison, so outcome<int>==result<int> etc + { + outcome<int> a(1); + result<int> b(1); + BOOST_CHECK(a == b); + BOOST_CHECK(b == a); + // result<void> e(in_place_type<void>), f(boost::system::errc::invalid_argument); + // BOOST_CHECK(a != e); + // BOOST_CHECK(a != f); + } + // Should I do outcome<int>(5) == 5? Unsure if it's wise +#endif +} diff --git a/src/boost/libs/outcome/test/tests/constexpr.cpp b/src/boost/libs/outcome/test/tests/constexpr.cpp new file mode 100644 index 000000000..327b8f26a --- /dev/null +++ b/src/boost/libs/outcome/test/tests/constexpr.cpp @@ -0,0 +1,118 @@ +/* Unit testing for outcomes +(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (9 commits) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#include <boost/outcome/outcome.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +#if __cplusplus >= 201700 || _HAS_CXX17 +// Match LiteralType, even on C++ 17 and later +template <class T> struct is_literal_type +{ + static constexpr bool value = // + std::is_void<T>::value // + || std::is_scalar<T>::value // + || std::is_reference<T>::value // + // leave out is_array for simplicity + || (std::is_class<T>::value && std::is_trivially_destructible<T>::value + // how does one detect if a type has at least one constexpr constructor without Reflection??? + ) // leave out union for simplicity + ; +}; +#else +template <class T> using is_literal_type = std::is_literal_type<T>; +#endif + +BOOST_OUTCOME_AUTO_TEST_CASE(works_outcome_constexpr, "Tests that outcome works as intended in a constexpr evaluation context") +{ + using namespace BOOST_OUTCOME_V2_NAMESPACE; + + static_assert(is_literal_type<result<int, void, void>>::value, "result<int, void, void> is not a literal type!"); + static_assert(is_literal_type<outcome<int, void, void>>::value, "outcome<int, void, void> is not a literal type!"); + + // Unfortunately result<T> can never be a literal type as error_code can never be literal + // + // It can however be trivially destructible as error_code is trivially destructible. That + // makes possible lots of compiler optimisations + static_assert(std::is_trivially_destructible<result<int>>::value, "result<int> is not trivially destructible!"); + static_assert(std::is_trivially_destructible<result<void>>::value, "result<void> is not trivially destructible!"); + + // outcome<T> default has no trivial operations, but if configured it can become so + static_assert(std::is_trivially_destructible<outcome<int, boost::system::error_code, void>>::value, + "outcome<int, boost::system::error_code, void> is not trivially destructible!"); + + { + // Test compatible results can be constructed from one another + constexpr result<int, long> g(in_place_type<int>, 5); + constexpr result<long, int> g2(g); + static_assert(g.has_value(), ""); + static_assert(!g.has_error(), ""); + static_assert(g.assume_value() == 5, ""); // value() with UDT E won't compile + static_assert(g2.has_value(), ""); + static_assert(!g2.has_error(), ""); + static_assert(g2.assume_value() == 5, ""); // value() with UDT E won't compile + constexpr result<void, int> g3(in_place_type<void>); + constexpr result<long, int> g4(g3); + constexpr result<int, void> g5(in_place_type<void>); + constexpr result<long, int> g6(g5); + (void) g4; + (void) g6; + + // Test void + constexpr result<void, int> h(in_place_type<void>); + static_assert(h.has_value(), ""); + constexpr result<int, void> h2(in_place_type<void>); + static_assert(!h2.has_value(), ""); + static_assert(h2.has_error(), ""); + + // Test const + constexpr result<const int, void> i(5); + constexpr result<const int, void> i2(i); + (void) i2; + } + { + // Test compatible outcomes can be constructed from one another + constexpr outcome<int, long, char *> g(in_place_type<int>, 5); + constexpr outcome<long, int, const char *> g2(g); + static_assert(g.has_value(), ""); + static_assert(!g.has_error(), ""); + static_assert(!g.has_exception(), ""); + static_assert(g.assume_value() == 5, ""); // value() with UDT E won't compile + static_assert(g2.has_value(), ""); + static_assert(!g2.has_error(), ""); + static_assert(!g2.has_exception(), ""); + static_assert(g2.assume_value() == 5, ""); // value() with UDT E won't compile + constexpr outcome<void, int, char *> g3(in_place_type<void>); + constexpr outcome<long, int, const char *> g4(g3); + constexpr outcome<int, void, char *> g5(in_place_type<void>); + constexpr outcome<long, int, const char *> g6(g5); + (void) g4; + (void) g6; + } +} diff --git a/src/boost/libs/outcome/test/tests/containers.cpp b/src/boost/libs/outcome/test/tests/containers.cpp new file mode 100644 index 000000000..b92af4b70 --- /dev/null +++ b/src/boost/libs/outcome/test/tests/containers.cpp @@ -0,0 +1,58 @@ +/* Unit testing for outcomes +(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (7 commits) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#include <boost/outcome/outcome.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +BOOST_OUTCOME_AUTO_TEST_CASE(works_outcome_containers, "Tests that outcome works as intended inside containers") +{ + using namespace BOOST_OUTCOME_V2_NAMESPACE; + outcome<std::vector<int>> a(std::vector<int>{5, 6, 7, 8}); + BOOST_CHECK(a.has_value()); + BOOST_CHECK(a.value().size() == 4U); + auto b(a); + BOOST_CHECK(a.has_value()); + BOOST_CHECK(a.value().size() == 4U); + BOOST_CHECK(b.has_value()); + BOOST_CHECK(b.value().size() == 4U); + + std::vector<outcome<std::vector<int>>> vect; + vect.push_back(std::vector<int>{5, 6, 7, 8}); + vect.push_back(std::vector<int>{1, 2, 3, 4}); + BOOST_REQUIRE(vect.size() == 2U); // NOLINT + BOOST_CHECK(vect[0].has_value()); + BOOST_CHECK(vect[1].has_value()); + BOOST_CHECK(vect[0].value().size() == 4U); + BOOST_CHECK(vect[1].value().size() == 4U); + BOOST_CHECK(vect[0].value().front() == 5); + BOOST_CHECK(vect[0].value().back() == 8); + BOOST_CHECK(vect[1].value().front() == 1); + BOOST_CHECK(vect[1].value().back() == 4); +} diff --git a/src/boost/libs/outcome/test/tests/core-outcome.cpp b/src/boost/libs/outcome/test/tests/core-outcome.cpp new file mode 100644 index 000000000..dfa15d355 --- /dev/null +++ b/src/boost/libs/outcome/test/tests/core-outcome.cpp @@ -0,0 +1,258 @@ +/* Unit testing for outcomes +(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (18 commits) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#include <boost/outcome/outcome.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +#include <iostream> + +#ifdef _MSC_VER +#pragma warning(disable : 4702) // unreachable code +#endif + +BOOST_OUTCOME_AUTO_TEST_CASE(works_outcome, "Tests that the outcome works as intended") +{ + using namespace BOOST_OUTCOME_V2_NAMESPACE; + + static_assert(std::is_constructible<outcome<long>, int>::value, "Sanity check that monad can be constructed from a value_type"); + static_assert(!std::is_constructible<outcome<outcome<long>>, int>::value, "Sanity check that outer monad can be constructed from an inner monad's value_type"); + static_assert(!std::is_constructible<outcome<outcome<outcome<long>>>, int>::value, "Sanity check that outer monad can be constructed from an inner inner monad's value_type"); + static_assert(!std::is_constructible<outcome<outcome<outcome<outcome<long>>>>, int>::value, "Sanity check that outer monad can be constructed from an inner inner monad's value_type"); + + static_assert(std::is_constructible<outcome<int>, outcome<long>>::value, "Sanity check that compatible monads can be constructed from one another"); + static_assert(std::is_constructible<outcome<outcome<int>>, outcome<long>>::value, "Sanity check that outer monad can be constructed from a compatible monad"); + static_assert(!std::is_constructible<outcome<outcome<outcome<int>>>, outcome<long>>::value, "Sanity check that outer monad can be constructed from a compatible monad up to two nestings deep"); + static_assert(!std::is_constructible<outcome<outcome<outcome<outcome<int>>>>, outcome<long>>::value, "Sanity check that outer monad can be constructed from a compatible monad three or more nestings deep"); + static_assert(!std::is_constructible<outcome<std::string>, outcome<int>>::value, "Sanity check that incompatible monads cannot be constructed from one another"); + + static_assert(std::is_constructible<outcome<int>, outcome<void>>::value, "Sanity check that all monads can be constructed from a void monad"); + static_assert(std::is_constructible<outcome<outcome<int>>, outcome<void>>::value, "Sanity check that outer monad can be constructed from a compatible monad"); + static_assert(std::is_constructible<outcome<outcome<outcome<int>>>, outcome<void>>::value, "Sanity check that outer monad can be constructed from a compatible monad up to two nestings deep"); + static_assert(!std::is_constructible<outcome<void>, outcome<int>>::value, "Sanity check that incompatible monads cannot be constructed from one another"); + + static_assert(std::is_void<result<void>::value_type>::value, "Sanity check that result<void> has a void value_type"); + static_assert(std::is_void<result<void, void>::error_type>::value, "Sanity check that result<void, void> has a void error_type"); + // static_assert(std::is_void<outcome<void, void, void>::exception_type>::value, "Sanity check that outcome<void, void, void> has a void exception_type"); + + static_assert(std::is_same<outcome<int>::value_type, int>::value, "Sanity check that outcome<int> has a int value_type"); + static_assert(std::is_same<outcome<int>::error_type, boost::system::error_code>::value, "Sanity check that outcome<int> has a error_code error_type"); + static_assert(std::is_same<outcome<int>::exception_type, boost::exception_ptr>::value, "Sanity check that outcome<int> has a exception_ptr exception_type"); + + + { // errored int + outcome<int> m(boost::system::errc::bad_address); + BOOST_CHECK(!m); + BOOST_CHECK(!m.has_value()); + BOOST_CHECK(m.has_error()); + BOOST_CHECK(!m.has_exception()); + BOOST_CHECK_THROW(m.value(), boost::system::system_error); + BOOST_CHECK_NO_THROW(m.error()); + BOOST_CHECK_THROW(m.exception(), bad_outcome_access); + BOOST_CHECK_THROW(boost::rethrow_exception(m.failure()), boost::system::system_error); + } + { // errored void + outcome<void> m(boost::system::errc::bad_address); + BOOST_CHECK(!m); + BOOST_CHECK(!m.has_value()); + BOOST_CHECK(m.has_error()); + BOOST_CHECK(!m.has_exception()); + BOOST_CHECK_THROW(([&m]() -> void { return m.value(); }()), boost::system::system_error); + BOOST_CHECK_NO_THROW(m.error()); + BOOST_CHECK_THROW(m.exception(), bad_outcome_access); + BOOST_CHECK_THROW(boost::rethrow_exception(m.failure()), boost::system::system_error); + } + { // valued int + outcome<int> m(5); + BOOST_CHECK(m); + BOOST_CHECK(m.has_value()); + BOOST_CHECK(!m.has_error()); + BOOST_CHECK(!m.has_exception()); + BOOST_CHECK(m.value() == 5); + m.value() = 6; + BOOST_CHECK(m.value() == 6); + BOOST_CHECK_THROW(m.error(), bad_outcome_access); + BOOST_CHECK_THROW(m.exception(), bad_outcome_access); + BOOST_CHECK(!m.failure()); + } + { // moves do not clear state + outcome<std::string> m("niall"); + BOOST_CHECK(m); + BOOST_CHECK(m.has_value()); + BOOST_CHECK(!m.has_error()); + BOOST_CHECK(!m.has_exception()); + BOOST_CHECK(m.value() == "niall"); + m.value() = "NIALL"; + BOOST_CHECK(m.value() == "NIALL"); + auto temp(std::move(m).value()); + BOOST_CHECK(temp == "NIALL"); + BOOST_CHECK(m.value().empty()); // NOLINT + } + { // valued void + outcome<void> m(in_place_type<void>); + BOOST_CHECK(m); + BOOST_CHECK(m.has_value()); + BOOST_CHECK(!m.has_error()); + BOOST_CHECK(!m.has_exception()); + BOOST_CHECK_NO_THROW(m.value()); // works, but type returned is unusable + BOOST_CHECK_THROW(m.error(), bad_outcome_access); + BOOST_CHECK_THROW(m.exception(), bad_outcome_access); + BOOST_CHECK(!m.failure()); + } + { // errored + boost::system::error_code ec(5, boost::system::system_category()); + outcome<int> m(ec); + BOOST_CHECK(!m); + BOOST_CHECK(!m.has_value()); + BOOST_CHECK(m.has_error()); + BOOST_CHECK(!m.has_exception()); + BOOST_CHECK_THROW(m.value(), boost::system::system_error); + BOOST_CHECK(m.error() == ec); + BOOST_CHECK_THROW(m.exception(), bad_outcome_access); +#ifndef BOOST_NO_EXCEPTIONS + BOOST_CHECK(m.failure()); + try + { + boost::rethrow_exception(m.failure()); + } + catch(const boost::system::system_error &ex) + { + BOOST_CHECK(ex.code() == ec); + BOOST_CHECK(ex.code().value() == 5); + } +#endif + } +#if !defined(__APPLE__) || defined(__cpp_exceptions) + { // excepted + boost::system::error_code ec(5, boost::system::system_category()); + auto e = boost::copy_exception(boost::system::system_error(ec)); // NOLINT + outcome<int> m(e); + BOOST_CHECK(!m); + BOOST_CHECK(!m.has_value()); + BOOST_CHECK(!m.has_error()); + BOOST_CHECK(m.has_exception()); + BOOST_CHECK_THROW(m.value(), boost::system::system_error); + BOOST_CHECK_THROW(m.error(), bad_outcome_access); + BOOST_CHECK(m.exception() == e); +#ifndef BOOST_NO_EXCEPTIONS + BOOST_CHECK(m.failure()); + try + { + boost::rethrow_exception(m.failure()); + } + catch(const boost::system::system_error &ex) + { + BOOST_CHECK(ex.code() == ec); + BOOST_CHECK(ex.code().value() == 5); + } +#endif + } + { // custom error type + struct Foo + { + }; + auto e = boost::copy_exception(Foo()); + outcome<int> m(e); + BOOST_CHECK(!m); + BOOST_CHECK(!m.has_value()); + BOOST_CHECK(!m.has_error()); + BOOST_CHECK(m.has_exception()); + BOOST_CHECK_THROW(m.value(), Foo); + BOOST_CHECK_THROW(m.error(), bad_outcome_access); + BOOST_CHECK(m.exception() == e); + } + { // outcome<void, void> should work + boost::system::error_code ec(5, boost::system::system_category()); + auto e = boost::copy_exception(boost::system::system_error(ec)); + outcome<void, void> m(e); + BOOST_CHECK(!m); + BOOST_CHECK(!m.has_value()); + BOOST_CHECK(!m.has_error()); + BOOST_CHECK(m.has_exception()); + } +#endif + + + { + outcome<int> a(5); + outcome<int> b(make_error_code(boost::system::errc::invalid_argument)); + std::cout << sizeof(a) << std::endl; // 40 bytes + a.assume_value(); + b.assume_error(); +#ifndef BOOST_NO_EXCEPTIONS + try + { + b.value(); + std::cerr << "fail" << std::endl; + std::terminate(); + } + catch(const boost::system::system_error & /*unused*/) + { + } +#endif + static_assert(!std::is_default_constructible<decltype(a)>::value, ""); + static_assert(!std::is_nothrow_default_constructible<decltype(a)>::value, ""); + static_assert(std::is_copy_constructible<decltype(a)>::value, ""); + static_assert(!std::is_trivially_copy_constructible<decltype(a)>::value, ""); + static_assert(std::is_nothrow_copy_constructible<decltype(a)>::value, ""); + static_assert(std::is_copy_assignable<decltype(a)>::value, ""); + static_assert(!std::is_trivially_copy_assignable<decltype(a)>::value, ""); + static_assert(std::is_nothrow_copy_assignable<decltype(a)>::value, ""); + static_assert(!std::is_trivially_destructible<decltype(a)>::value, ""); + static_assert(std::is_nothrow_destructible<decltype(a)>::value, ""); + + // Test void compiles + outcome<void> c(in_place_type<void>); + outcome<void> c2(c); + (void) c2; + // Test int, void compiles + outcome<int, void> d(in_place_type<boost::exception_ptr>); + } + + { + // Can only be constructed via multiple args + struct udt3 + { + udt3() = delete; + udt3(udt3 &&) = delete; + udt3(const udt3 &) = delete; + udt3 &operator=(udt3 &&) = delete; + udt3 &operator=(const udt3 &) = delete; + explicit udt3(int /*unused*/, const char * /*unused*/, std::nullptr_t /*unused*/) {} + ~udt3() = default; + }; + // Test a udt which can only be constructed in place compiles + outcome<udt3> g(in_place_type<udt3>, 5, static_cast<const char *>("niall"), nullptr); + // Does converting inplace construction also work? + outcome<udt3> h(5, static_cast<const char *>("niall"), nullptr); + outcome<udt3> i(ENOMEM, boost::system::generic_category()); + BOOST_CHECK(h.has_value()); + BOOST_CHECK(i.has_error()); + } +} diff --git a/src/boost/libs/outcome/test/tests/core-result.cpp b/src/boost/libs/outcome/test/tests/core-result.cpp new file mode 100644 index 000000000..2ded9cb6a --- /dev/null +++ b/src/boost/libs/outcome/test/tests/core-result.cpp @@ -0,0 +1,370 @@ +/* Unit testing for outcomes +(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (30 commits) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#ifdef TESTING_WG21_EXPERIMENTAL_RESULT +#include <boost/outcome/experimental/result.hpp> +#define BOOST_OUTCOME_AUTO_TEST_CASE(...) BOOST_AUTO_TEST_CASE(__VA_ARGS__) +#else +#include <boost/outcome/result.hpp> +#endif +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +#include <iostream> + +#ifndef BOOST_NO_EXCEPTIONS +// Custom error type with payload +struct payload +{ + boost::system::error_code ec; + const char *str{nullptr}; + payload() = default; + payload(boost::system::errc::errc_t _ec, const char *_str) + : ec(make_error_code(_ec)) + , str(_str) + { + } +}; +struct payload_exception : std::runtime_error +{ + explicit payload_exception(const char *what) + : std::runtime_error(what) + { + } +}; +inline const boost::system::error_code &make_error_code(const payload &p) +{ + return p.ec; +} +inline void outcome_throw_as_system_error_with_payload(const payload &p) +{ + throw payload_exception(p.str); +} +#endif + +BOOST_OUTCOME_AUTO_TEST_CASE(works_result, "Tests that the result works as intended") +{ +#ifdef TESTING_WG21_EXPERIMENTAL_RESULT + using namespace std::experimental; + using std::in_place_type; +#else + using namespace BOOST_OUTCOME_V2_NAMESPACE; +#endif + + static_assert(std::is_constructible<result<long>, int>::value, "Sanity check that monad can be constructed from a value_type"); + 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"); + 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"); + 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"); + + static_assert(std::is_constructible<result<int>, result<long>>::value, "Sanity check that compatible monads can be constructed from one another"); + static_assert(std::is_constructible<result<result<int>>, result<long>>::value, "Sanity check that outer monad can be constructed from a compatible monad"); + 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"); + 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"); + static_assert(!std::is_constructible<result<std::string>, result<int>>::value, "Sanity check that incompatible monads cannot be constructed from one another"); + +#ifndef TESTING_WG21_EXPERIMENTAL_RESULT + static_assert(std::is_constructible<result<int>, result<void>>::value, "Sanity check that all monads can be constructed from a void monad"); + static_assert(std::is_constructible<result<result<int>>, result<void>>::value, "Sanity check that outer monad can be constructed from a compatible monad"); + 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"); + static_assert(!std::is_constructible<result<void>, result<int>>::value, "Sanity check that incompatible monads cannot be constructed from one another"); +#endif + static_assert(std::is_void<result<void>::value_type>::value, "Sanity check that result<void> has a void value_type"); +#ifndef TESTING_WG21_EXPERIMENTAL_RESULT + static_assert(std::is_void<result<void, void>::error_type>::value, "Sanity check that result<void, void> has a void error_type"); +#endif + + static_assert(std::is_same<result<int>::value_type, int>::value, "Sanity check that result<int> has a int value_type"); + 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"); + + + { // errored int + result<int> m(boost::system::errc::bad_address); + BOOST_CHECK(!m); + BOOST_CHECK(!m.has_value()); + BOOST_CHECK(m.has_error()); + // BOOST_CHECK(!m.has_exception()); + BOOST_CHECK_THROW(m.value(), boost::system::system_error); + BOOST_CHECK_NO_THROW(m.error()); + } + { // errored void + result<void> m(boost::system::errc::bad_address); + BOOST_CHECK(!m); + BOOST_CHECK(!m.has_value()); + BOOST_CHECK(m.has_error()); +// BOOST_CHECK(!m.has_exception()); +#ifndef TESTING_WG21_EXPERIMENTAL_RESULT + BOOST_CHECK_THROW(([&m]() -> void { return m.value(); }()), boost::system::system_error); +#endif + BOOST_CHECK_NO_THROW(m.error()); + } + { // valued int + result<int> m(5); + BOOST_CHECK(m); + BOOST_CHECK(m.has_value()); + BOOST_CHECK(!m.has_error()); + // BOOST_CHECK(!m.has_exception()); + BOOST_CHECK(m.value() == 5); + m.value() = 6; + BOOST_CHECK(m.value() == 6); + BOOST_CHECK_THROW(m.error(), bad_result_access); + } + { // valued bool + result<bool> m(false); + BOOST_CHECK(m); + BOOST_CHECK(m.has_value()); + BOOST_CHECK(!m.has_error()); + // BOOST_CHECK(!m.has_exception()); + BOOST_CHECK(m.value() == false); + m.value() = true; + BOOST_CHECK(m.value() == true); + BOOST_CHECK_THROW(m.error(), bad_result_access); + } + { // moves do not clear state + result<std::string> m("niall"); + BOOST_CHECK(m); + BOOST_CHECK(m.has_value()); + BOOST_CHECK(!m.has_error()); + // BOOST_CHECK(!m.has_exception()); + BOOST_CHECK(m.value() == "niall"); + m.value() = "NIALL"; + BOOST_CHECK(m.value() == "NIALL"); + auto temp(std::move(m).value()); + BOOST_CHECK(temp == "NIALL"); + BOOST_CHECK(m.value().empty()); // NOLINT + } + { // valued void + result<void> m(in_place_type<void>); + BOOST_CHECK(m); + BOOST_CHECK(m.has_value()); + BOOST_CHECK(!m.has_error()); + // BOOST_CHECK(!m.has_exception()); + BOOST_CHECK_NO_THROW(m.value()); // works, but type returned is unusable + BOOST_CHECK_THROW(m.error(), bad_result_access); + } + { // errored + boost::system::error_code ec(5, boost::system::system_category()); + result<int> m(ec); + BOOST_CHECK(!m); + BOOST_CHECK(!m.has_value()); + BOOST_CHECK(m.has_error()); + // BOOST_CHECK(!m.has_exception()); + BOOST_CHECK_THROW(m.value(), boost::system::system_error); + BOOST_CHECK(m.error() == ec); + } +#if !defined(__APPLE__) || defined(__cpp_exceptions) + { // errored, custom + boost::system::error_code ec(5, boost::system::system_category()); + auto e = boost::copy_exception(boost::system::system_error(ec)); // NOLINT + result<int, boost::exception_ptr> m(e); + BOOST_CHECK(!m); + BOOST_CHECK(!m.has_value()); + BOOST_CHECK(m.has_error()); + // BOOST_CHECK(!m.has_exception()); + BOOST_CHECK_THROW(m.value(), boost::system::system_error); + BOOST_CHECK(m.error() == e); + } +#endif +#ifndef TESTING_WG21_EXPERIMENTAL_RESULT + { // custom error type + struct Foo + { + }; + result<int, Foo> m(in_place_type<Foo>); + BOOST_CHECK(!m); + BOOST_CHECK(!m.has_value()); + BOOST_CHECK(m.has_error()); + // BOOST_CHECK(!m.has_exception()); + // BOOST_CHECK_NO_THROW(m.value()); + // BOOST_CHECK_NO_THROW(m.error()); + } + if(false) // NOLINT + { // void, void is permitted, but is not constructible + result<void, void> *m = nullptr; + m->value(); + m->error(); + } +#endif + + { + // Deliberately define non-trivial operations + struct udt + { + int _v{0}; + udt() = default; + udt(udt &&o) noexcept : _v(o._v) {} + udt(const udt &o) // NOLINT + : _v(o._v) + { + } + udt &operator=(udt &&o) noexcept + { + _v = o._v; + return *this; + } + udt &operator=(const udt &o) // NOLINT + { + _v = o._v; + return *this; + } + ~udt() { _v = 0; } + }; + // No default construction, no copy nor move + struct udt2 + { + udt2() = delete; + udt2(udt2 &&) = delete; + udt2(const udt2 &) = delete; + udt2 &operator=(udt2 &&) = delete; + udt2 &operator=(const udt2 &) = delete; + explicit udt2(int /*unused*/) {} + ~udt2() = default; + }; + // Can only be constructed via multiple args + struct udt3 + { + udt3() = delete; + udt3(udt3 &&) = delete; + udt3(const udt3 &) = delete; + udt3 &operator=(udt3 &&) = delete; + udt3 &operator=(const udt3 &) = delete; + explicit udt3(int /*unused*/, const char * /*unused*/, std::nullptr_t /*unused*/) {} + ~udt3() = default; + }; + + + result<int> a(5); + result<int> b(make_error_code(boost::system::errc::invalid_argument)); + std::cout << sizeof(a) << std::endl; // 32 bytes + if(false) // NOLINT + { + b.assume_value(); + a.assume_error(); + } +#ifndef BOOST_NO_EXCEPTIONS + try + { + b.value(); + std::cerr << "fail" << std::endl; + std::terminate(); + } + catch(const boost::system::system_error & /*unused*/) + { + } +#endif + static_assert(!std::is_default_constructible<decltype(a)>::value, ""); + static_assert(!std::is_nothrow_default_constructible<decltype(a)>::value, ""); + static_assert(std::is_copy_constructible<decltype(a)>::value, ""); +// Quality of implementation of std::optional is poor :( +#ifndef TESTING_WG21_EXPERIMENTAL_RESULT + static_assert(std::is_trivially_copy_constructible<decltype(a)>::value, ""); + static_assert(std::is_nothrow_copy_constructible<decltype(a)>::value, ""); + static_assert(std::is_copy_assignable<decltype(a)>::value, ""); + static_assert(std::is_trivially_copy_assignable<decltype(a)>::value, ""); + static_assert(std::is_nothrow_copy_assignable<decltype(a)>::value, ""); +#endif + static_assert(std::is_trivially_destructible<decltype(a)>::value, ""); + static_assert(std::is_nothrow_destructible<decltype(a)>::value, ""); + + // Test void compiles + result<void> c(in_place_type<void>); + result<void> c2(c); + (void) c2; + + // Test a standard udt compiles + result<udt> d(in_place_type<udt>); + result<udt> d2(d); + static_assert(!std::is_default_constructible<decltype(d)>::value, ""); + static_assert(!std::is_nothrow_default_constructible<decltype(d)>::value, ""); + static_assert(std::is_copy_constructible<decltype(d)>::value, ""); + static_assert(!std::is_trivially_copy_constructible<decltype(d)>::value, ""); + static_assert(!std::is_nothrow_copy_constructible<decltype(d)>::value, ""); + static_assert(std::is_copy_assignable<decltype(d)>::value, ""); + static_assert(!std::is_trivially_copy_assignable<decltype(d)>::value, ""); + static_assert(!std::is_nothrow_copy_assignable<decltype(d)>::value, ""); + static_assert(std::is_move_assignable<decltype(d)>::value, ""); + static_assert(!std::is_trivially_move_assignable<decltype(d)>::value, ""); + static_assert(std::is_nothrow_move_assignable<decltype(d)>::value, ""); + static_assert(!std::is_trivially_destructible<decltype(d)>::value, ""); + static_assert(std::is_nothrow_destructible<decltype(d)>::value, ""); + + // Test a highly pathological udt compiles + result<udt2> e(in_place_type<udt2>, 5); + // result<udt2> e2(e); + static_assert(!std::is_default_constructible<decltype(e)>::value, ""); + static_assert(!std::is_nothrow_default_constructible<decltype(e)>::value, ""); + static_assert(!std::is_copy_constructible<decltype(e)>::value, ""); + static_assert(!std::is_trivially_copy_constructible<decltype(e)>::value, ""); + static_assert(!std::is_nothrow_copy_constructible<decltype(e)>::value, ""); + static_assert(!std::is_copy_assignable<decltype(e)>::value, ""); + static_assert(!std::is_trivially_copy_assignable<decltype(e)>::value, ""); + static_assert(!std::is_nothrow_copy_assignable<decltype(e)>::value, ""); + static_assert(!std::is_move_assignable<decltype(e)>::value, ""); + static_assert(!std::is_trivially_move_assignable<decltype(e)>::value, ""); + static_assert(!std::is_nothrow_move_assignable<decltype(e)>::value, ""); + + // Test a udt which can only be constructed in place compiles + result<udt3> g(in_place_type<udt3>, 5, static_cast<const char *>("niall"), nullptr); + // Does converting inplace construction also work? + result<udt3> h(5, static_cast<const char *>("niall"), nullptr); + result<udt3> i(ENOMEM, boost::system::generic_category()); + BOOST_CHECK(h.has_value()); + BOOST_CHECK(i.has_error()); + } + + // Test direct use of error code enum works + { + constexpr result<int, boost::system::errc::errc_t> a(5), b(boost::system::errc::invalid_argument); + static_assert(a.value() == 5, "a is not 5"); + static_assert(b.error() == boost::system::errc::invalid_argument, "b is not errored"); + BOOST_CHECK_THROW(b.value(), boost::system::system_error); + } + +#ifndef TESTING_WG21_EXPERIMENTAL_RESULT +#ifndef BOOST_NO_EXCEPTIONS + // Test payload facility + { + const char *niall = "niall"; + result<int, payload> b{boost::system::errc::invalid_argument, niall}; + try + { + b.value(); + BOOST_CHECK(false); + } + catch(const payload_exception &e) + { + BOOST_CHECK(!strcmp(e.what(), niall)); + } + catch(...) + { + BOOST_CHECK(false); + } + } +#endif +#endif +} diff --git a/src/boost/libs/outcome/test/tests/coroutine-support.cpp b/src/boost/libs/outcome/test/tests/coroutine-support.cpp new file mode 100644 index 000000000..43c46b09b --- /dev/null +++ b/src/boost/libs/outcome/test/tests/coroutine-support.cpp @@ -0,0 +1,120 @@ +/* Unit testing for outcomes +(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (6 commits) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#if defined(__cpp_coroutines) + +#include <boost/outcome/coroutine_support.hpp> +#include <boost/outcome/outcome.hpp> +#include <boost/outcome/try.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +namespace coroutines +{ + template <class T> using eager = BOOST_OUTCOME_V2_NAMESPACE::awaitables::eager<T>; + template <class T> using lazy = BOOST_OUTCOME_V2_NAMESPACE::awaitables::lazy<T>; + template <class T, class E = boost::system::error_code> using result = BOOST_OUTCOME_V2_NAMESPACE::result<T, E>; + + inline eager<result<int>> eager_int(int x) { co_return x + 1; } + inline lazy<result<int>> lazy_int(int x) { co_return x + 1; } + inline eager<result<int>> eager_error() { co_return boost::system::errc::not_enough_memory; } + inline lazy<result<int>> lazy_error() { co_return boost::system::errc::not_enough_memory; } + inline eager<result<void>> eager_void() { co_return boost::system::errc::not_enough_memory; } + inline lazy<result<void>> lazy_void() { co_return boost::system::errc::not_enough_memory; } + + template <class U, class... Args> inline eager<result<std::string>> eager_coawait(U &&f, Args... args) + { + BOOST_OUTCOME_CO_TRY(co_await f(args...)); + co_return "hi"; + } + template <class U, class... Args> inline lazy<result<std::string>> lazy_coawait(U &&f, Args... args) + { + BOOST_OUTCOME_CO_TRY(co_await f(args...)); + co_return "hi"; + } + +#ifndef BOOST_NO_EXCEPTIONS + struct custom_exception_type + { + }; + inline lazy<result<int, boost::exception_ptr>> result_exception(boost::exception_ptr e) + { + boost::rethrow_exception(e); + co_return 5; + } + + inline lazy<BOOST_OUTCOME_V2_NAMESPACE::outcome<int>> outcome_exception(boost::exception_ptr e) + { + boost::rethrow_exception(e); + co_return 5; + } +#endif + + inline eager<int> eager_int2(int x) { co_return x + 1; } + inline lazy<int> lazy_int2(int x) { co_return x + 1; } + inline eager<void> eager_void2() { co_return; } + inline lazy<void> lazy_void2() { co_return; } +} // namespace coroutines + +BOOST_OUTCOME_AUTO_TEST_CASE(works_result_coroutine, "Tests that results are eager and lazy awaitable") +{ + using namespace coroutines; + auto eager_await = [](auto t) { return t.await_resume(); }; + auto lazy_await = [](auto t) { + t.await_suspend({}); + return t.await_resume(); + }; + + BOOST_CHECK(eager_await(eager_int(5)).value() == 6); + BOOST_CHECK(lazy_await(lazy_int(5)).value() == 6); + BOOST_CHECK(eager_await(eager_error()).error() == boost::system::errc::not_enough_memory); + BOOST_CHECK(lazy_await(lazy_error()).error() == boost::system::errc::not_enough_memory); + BOOST_CHECK(eager_await(eager_void()).error() == boost::system::errc::not_enough_memory); + BOOST_CHECK(lazy_await(lazy_void()).error() == boost::system::errc::not_enough_memory); + + BOOST_CHECK(eager_await(eager_coawait(eager_int, 5)).value() == "hi"); + BOOST_CHECK(lazy_await(lazy_coawait(lazy_int, 5)).value() == "hi"); + +#ifndef BOOST_NO_EXCEPTIONS + auto e = boost::copy_exception(custom_exception_type()); + BOOST_CHECK_THROW(lazy_await(result_exception(e)).value(), custom_exception_type); + BOOST_CHECK_THROW(lazy_await(outcome_exception(e)).value(), custom_exception_type); +#endif + + BOOST_CHECK(eager_await(eager_int2(5)) == 6); + BOOST_CHECK(lazy_await(lazy_int2(5)) == 6); + eager_await(eager_void2()); + lazy_await(lazy_void2()); +} +#else +int main(void) +{ + return 0; +} +#endif diff --git a/src/boost/libs/outcome/test/tests/default-construction.cpp b/src/boost/libs/outcome/test/tests/default-construction.cpp new file mode 100644 index 000000000..25726abb4 --- /dev/null +++ b/src/boost/libs/outcome/test/tests/default-construction.cpp @@ -0,0 +1,57 @@ +/* Unit testing for outcomes +(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (4 commits) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#include <boost/outcome/outcome.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +BOOST_OUTCOME_AUTO_TEST_CASE(works_outcome_default_construction, "Tests that outcome default constructs when it ought to") +{ + using namespace BOOST_OUTCOME_V2_NAMESPACE; + struct udt + { + int _v{78}; + udt() = default; + constexpr explicit udt(int v) noexcept : _v(v) {} + udt(udt &&o) = delete; + udt(const udt &) = delete; + udt &operator=(udt &&o) = delete; + udt &operator=(const udt &) = delete; + ~udt() = default; + constexpr int operator*() const noexcept { return _v; } + }; + // One path is via success_type<void> + outcome<udt> a(success()); + BOOST_CHECK(*a.value() == 78); + + // Other path is via explicit conversion from void + outcome<void> c = success(); + outcome<udt> d(c); + BOOST_CHECK(*d.value() == 78); +} diff --git a/src/boost/libs/outcome/test/tests/experimental-core-outcome-status.cpp b/src/boost/libs/outcome/test/tests/experimental-core-outcome-status.cpp new file mode 100644 index 000000000..b7aed1d8c --- /dev/null +++ b/src/boost/libs/outcome/test/tests/experimental-core-outcome-status.cpp @@ -0,0 +1,225 @@ +/* Unit testing for outcomes +(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (4 commits) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#include <boost/outcome/experimental/status_outcome.hpp> + +#define BOOST_OUTCOME_PREVENT_CONVERSION_WORKAROUND std +template <class T, class S = BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::system_code, class P = BOOST_OUTCOME_PREVENT_CONVERSION_WORKAROUND::exception_ptr> using outcome = BOOST_OUTCOME_V2_NAMESPACE::experimental::status_outcome<T, S, P>; +using BOOST_OUTCOME_V2_NAMESPACE::in_place_type; + +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +#include <iostream> + +#ifdef _MSC_VER +#pragma warning(disable : 4702) // unreachable code +#endif + +BOOST_OUTCOME_AUTO_TEST_CASE(works_status_code_outcome, "Tests that the outcome with status_code works as intended") +{ + using namespace BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE; + + { // errored int + outcome<int> m(generic_code{errc::bad_address}); + BOOST_CHECK(!m); + BOOST_CHECK(!m.has_value()); + BOOST_CHECK(m.has_error()); + BOOST_CHECK(!m.has_exception()); + BOOST_CHECK_THROW(m.value(), status_error<void>); + BOOST_CHECK_NO_THROW(m.error()); + BOOST_CHECK_THROW(BOOST_OUTCOME_PREVENT_CONVERSION_WORKAROUND::rethrow_exception(m.failure()), generic_error); + } + { // errored void + outcome<void> m(generic_code{errc::bad_address}); + BOOST_CHECK(!m); + BOOST_CHECK(!m.has_value()); + BOOST_CHECK(m.has_error()); + BOOST_CHECK(!m.has_exception()); + BOOST_CHECK_THROW(([&m]() -> void { return m.value(); }()), generic_error); + BOOST_CHECK_NO_THROW(m.error()); + BOOST_CHECK_THROW(BOOST_OUTCOME_PREVENT_CONVERSION_WORKAROUND::rethrow_exception(m.failure()), generic_error); + } + { // valued int + outcome<int> m(5); + BOOST_CHECK(m); + BOOST_CHECK(m.has_value()); + BOOST_CHECK(!m.has_error()); + BOOST_CHECK(!m.has_exception()); + BOOST_CHECK(m.value() == 5); + m.value() = 6; + BOOST_CHECK(m.value() == 6); + BOOST_CHECK(!m.failure()); + } + { // moves do not clear state + outcome<std::string> m("niall"); + BOOST_CHECK(m); + BOOST_CHECK(m.has_value()); + BOOST_CHECK(!m.has_error()); + BOOST_CHECK(!m.has_exception()); + BOOST_CHECK(m.value() == "niall"); + m.value() = "NIALL"; + BOOST_CHECK(m.value() == "NIALL"); + auto temp(std::move(m).value()); + BOOST_CHECK(temp == "NIALL"); + BOOST_CHECK(m.value().empty()); // NOLINT + } + { // valued void + outcome<void> m(in_place_type<void>); + BOOST_CHECK(m); + BOOST_CHECK(m.has_value()); + BOOST_CHECK(!m.has_error()); + BOOST_CHECK(!m.has_exception()); + BOOST_CHECK_NO_THROW(m.value()); // works, but type returned is unusable + BOOST_CHECK(!m.failure()); + } + { // errored + error ec(errc::no_link); + outcome<int> m(ec.clone()); + BOOST_CHECK(!m); + BOOST_CHECK(!m.has_value()); + BOOST_CHECK(m.has_error()); + BOOST_CHECK(!m.has_exception()); + BOOST_CHECK_THROW(m.value(), generic_error); + BOOST_CHECK(m.error() == ec); +#ifndef BOOST_NO_EXCEPTIONS + BOOST_CHECK(m.failure()); + try + { + BOOST_OUTCOME_PREVENT_CONVERSION_WORKAROUND::rethrow_exception(m.failure()); + } + catch(const generic_error &ex) + { + BOOST_CHECK(ex.code() == ec); + BOOST_CHECK(ex.code().value() == errc::no_link); + } +#endif + } +#if !defined(__APPLE__) || defined(__cpp_exceptions) + { // excepted + BOOST_OUTCOME_PREVENT_CONVERSION_WORKAROUND::error_code ec(5, BOOST_OUTCOME_PREVENT_CONVERSION_WORKAROUND::system_category()); + auto e = BOOST_OUTCOME_PREVENT_CONVERSION_WORKAROUND::make_exception_ptr(BOOST_OUTCOME_PREVENT_CONVERSION_WORKAROUND::system_error(ec)); // NOLINT + outcome<int> m(e); + BOOST_CHECK(!m); + BOOST_CHECK(!m.has_value()); + BOOST_CHECK(!m.has_error()); + BOOST_CHECK(m.has_exception()); + BOOST_CHECK_THROW(m.value(), BOOST_OUTCOME_PREVENT_CONVERSION_WORKAROUND::system_error); + BOOST_CHECK(m.exception() == e); +#ifndef BOOST_NO_EXCEPTIONS + BOOST_CHECK(m.failure()); + try + { + BOOST_OUTCOME_PREVENT_CONVERSION_WORKAROUND::rethrow_exception(m.failure()); + } + catch(const BOOST_OUTCOME_PREVENT_CONVERSION_WORKAROUND::system_error &ex) + { + BOOST_CHECK(ex.code() == ec); + BOOST_CHECK(ex.code().value() == 5); + } +#endif + } + { // custom error type + struct Foo + { + }; + auto e = BOOST_OUTCOME_PREVENT_CONVERSION_WORKAROUND::make_exception_ptr(Foo()); + outcome<int> m(e); + BOOST_CHECK(!m); + BOOST_CHECK(!m.has_value()); + BOOST_CHECK(!m.has_error()); + BOOST_CHECK(m.has_exception()); + BOOST_CHECK_THROW(m.value(), Foo); + BOOST_CHECK(m.exception() == e); + } + { // outcome<void, void> should work + BOOST_OUTCOME_PREVENT_CONVERSION_WORKAROUND::error_code ec(5, BOOST_OUTCOME_PREVENT_CONVERSION_WORKAROUND::system_category()); + auto e = BOOST_OUTCOME_PREVENT_CONVERSION_WORKAROUND::make_exception_ptr(BOOST_OUTCOME_PREVENT_CONVERSION_WORKAROUND::system_error(ec)); + outcome<void, void> m(e); + BOOST_CHECK(!m); + BOOST_CHECK(!m.has_value()); + BOOST_CHECK(!m.has_error()); + BOOST_CHECK(m.has_exception()); + } +#endif + + + { + outcome<int> a(5); + outcome<int> b(generic_code{errc::invalid_argument}); + std::cout << sizeof(a) << std::endl; // 40 bytes + a.assume_value(); + b.assume_error(); +#ifndef BOOST_NO_EXCEPTIONS + try + { + b.value(); + std::cerr << "fail" << std::endl; + std::terminate(); + } + catch(const generic_error & /*unused*/) + { + } +#endif + static_assert(!std::is_default_constructible<decltype(a)>::value, ""); + static_assert(!std::is_nothrow_default_constructible<decltype(a)>::value, ""); + static_assert(!std::is_copy_constructible<decltype(a)>::value, ""); + static_assert(!std::is_trivially_copy_constructible<decltype(a)>::value, ""); + static_assert(!std::is_nothrow_copy_constructible<decltype(a)>::value, ""); + static_assert(!std::is_copy_assignable<decltype(a)>::value, ""); + static_assert(!std::is_trivially_copy_assignable<decltype(a)>::value, ""); + static_assert(!std::is_nothrow_copy_assignable<decltype(a)>::value, ""); + static_assert(!std::is_trivially_destructible<decltype(a)>::value, ""); + static_assert(std::is_nothrow_destructible<decltype(a)>::value, ""); + + // Test void compiles + outcome<void> c(in_place_type<void>); + // Test int, void compiles + outcome<int, void> d(in_place_type<BOOST_OUTCOME_PREVENT_CONVERSION_WORKAROUND::exception_ptr>); + } + + { + // Can only be constructed via multiple args + struct udt3 + { + udt3() = delete; + udt3(udt3 &&) = delete; + udt3(const udt3 &) = delete; + udt3 &operator=(udt3 &&) = delete; + udt3 &operator=(const udt3 &) = delete; + explicit udt3(int /*unused*/, const char * /*unused*/, std::nullptr_t /*unused*/) {} + ~udt3() = default; + }; + // Test a udt which can only be constructed in place compiles + outcome<udt3> g(in_place_type<udt3>, 5, static_cast<const char *>("niall"), nullptr); + // Does converting inplace construction also work? + outcome<udt3> h(5, static_cast<const char *>("niall"), nullptr); + BOOST_CHECK(h.has_value()); + } +} diff --git a/src/boost/libs/outcome/test/tests/experimental-core-result-status.cpp b/src/boost/libs/outcome/test/tests/experimental-core-result-status.cpp new file mode 100644 index 000000000..085c13dd2 --- /dev/null +++ b/src/boost/libs/outcome/test/tests/experimental-core-result-status.cpp @@ -0,0 +1,357 @@ +/* Unit testing for outcomes +(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (8 commits) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#include <boost/outcome/experimental/status_result.hpp> + +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>; +using BOOST_OUTCOME_V2_NAMESPACE::in_place_type; + +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +#include <exception> +#include <iostream> + +#ifndef BOOST_NO_EXCEPTIONS +// Custom error type with payload +struct payload +{ + BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::errc ec{BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::errc::success}; + const char *str{nullptr}; + payload() = default; + payload(BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::errc _ec, const char *_str) + : ec(_ec) + , str(_str) + { + } +}; +struct payload_exception : std::exception +{ + const char *_what{nullptr}; + explicit payload_exception(const char *what) + : _what(what) + { + } + virtual const char *what() const noexcept override final { return _what; } // NOLINT +}; + +class _payload_domain; +using status_code_payload = BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code<_payload_domain>; +class _payload_domain : public BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code_domain +{ + template <class> friend class status_code; + using _base = BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code_domain; + +public: + using value_type = payload; + using string_ref = _base::string_ref; + +public: + constexpr _payload_domain() noexcept : _base(0x7b782c8f935e34ba) {} + + static inline constexpr const _payload_domain &get(); + + virtual _base::string_ref name() const noexcept override final { return string_ref("payload domain"); } // NOLINT +protected: + virtual bool _do_failure(const BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code<void> &code) const noexcept override final // NOLINT + { + assert(code.domain() == *this); // NOLINT + return static_cast<const status_code_payload &>(code).value().ec != BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::errc::success; // NOLINT + } + 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 + { + assert(code1.domain() == *this); // NOLINT + const auto &c1 = static_cast<const status_code_payload &>(code1); // NOLINT + if(code2.domain() == *this) + { + const auto &c2 = static_cast<const status_code_payload &>(code2); // NOLINT + return c1.value().ec == c2.value().ec; + } + return false; + } + 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 + { + assert(code.domain() == *this); // NOLINT + return static_cast<const status_code_payload &>(code).value().ec; // NOLINT + } + virtual _base::string_ref _do_message(const BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code<void> &code) const noexcept override final // NOLINT + { + assert(code.domain() == *this); // NOLINT + const auto &c = static_cast<const status_code_payload &>(code); // NOLINT + return string_ref(BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::detail::generic_code_message(c.value().ec)); + } + virtual void _do_throw_exception(const BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code<void> &code) const override final // NOLINT + { + assert(code.domain() == *this); // NOLINT + const auto &c = static_cast<const status_code_payload &>(code); // NOLINT + throw payload_exception(c.value().str); + } +}; +constexpr _payload_domain payload_domain; +inline constexpr const _payload_domain &_payload_domain::get() +{ + return payload_domain; +} +inline status_code_payload make_status_code(payload c) noexcept +{ + return status_code_payload(BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::in_place, c); +} +#endif + +BOOST_OUTCOME_AUTO_TEST_CASE(works_status_code_result, "Tests that the result with status_code works as intended") +{ + using namespace BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE; + + { // errored int + result<int> m(generic_code{errc::bad_address}); + BOOST_CHECK(!m); + BOOST_CHECK(!m.has_value()); + BOOST_CHECK(m.has_error()); + // BOOST_CHECK(!m.has_exception()); + BOOST_CHECK_THROW(m.value(), generic_error); + BOOST_CHECK_NO_THROW(m.error()); + } + { // errored void + result<void> m(generic_code{errc::bad_address}); + BOOST_CHECK(!m); + BOOST_CHECK(!m.has_value()); + BOOST_CHECK(m.has_error()); + // BOOST_CHECK(!m.has_exception()); + BOOST_CHECK_THROW(([&m]() -> void { return m.value(); }()), generic_error); + BOOST_CHECK_NO_THROW(m.error()); + } + { // valued int + result<int> m(5); + BOOST_CHECK(m); + BOOST_CHECK(m.has_value()); + BOOST_CHECK(!m.has_error()); + // BOOST_CHECK(!m.has_exception()); + BOOST_CHECK(m.value() == 5); + m.value() = 6; + BOOST_CHECK(m.value() == 6); + } + { // valued bool + result<bool> m(false); + BOOST_CHECK(m); + BOOST_CHECK(m.has_value()); + BOOST_CHECK(!m.has_error()); + // BOOST_CHECK(!m.has_exception()); + BOOST_CHECK(m.value() == false); + m.value() = true; + BOOST_CHECK(m.value() == true); + } + { // moves do not clear state + result<std::string> m("niall"); + BOOST_CHECK(m); + BOOST_CHECK(m.has_value()); + BOOST_CHECK(!m.has_error()); + // BOOST_CHECK(!m.has_exception()); + BOOST_CHECK(m.value() == "niall"); + m.value() = "NIALL"; + BOOST_CHECK(m.value() == "NIALL"); + auto temp(std::move(m).value()); + BOOST_CHECK(temp == "NIALL"); + BOOST_CHECK(m.value().empty()); // NOLINT + } + { // valued void + result<void> m(in_place_type<void>); + BOOST_CHECK(m); + BOOST_CHECK(m.has_value()); + BOOST_CHECK(!m.has_error()); + // BOOST_CHECK(!m.has_exception()); + BOOST_CHECK_NO_THROW(m.value()); // works, but type returned is unusable + } + { // errored + error ec(errc::no_link); + result<int> m(ec.clone()); + BOOST_CHECK(!m); + BOOST_CHECK(!m.has_value()); + BOOST_CHECK(m.has_error()); + // BOOST_CHECK(!m.has_exception()); + BOOST_CHECK_THROW(m.value(), generic_error); + BOOST_CHECK(m.error() == ec); + } + if(false) // NOLINT + { // void, void is permitted, but is not constructible + result<void, void> *m = nullptr; + m->value(); + m->error(); + } + + { + // Deliberately define non-trivial operations + struct udt + { + int _v{0}; + udt() = default; + udt(udt &&o) noexcept : _v(o._v) {} + udt(const udt &o) // NOLINT + : _v(o._v) + { + } + udt &operator=(udt &&o) noexcept + { + _v = o._v; + return *this; + } + udt &operator=(const udt &o) // NOLINT + { + _v = o._v; + return *this; + } + ~udt() { _v = 0; } + }; + // No default construction, no copy nor move + struct udt2 + { + udt2() = delete; + udt2(udt2 &&) = delete; + udt2(const udt2 &) = delete; + udt2 &operator=(udt2 &&) = delete; + udt2 &operator=(const udt2 &) = delete; + explicit udt2(int /*unused*/) {} + ~udt2() = default; + }; + // Can only be constructed via multiple args + struct udt3 + { + udt3() = delete; + udt3(udt3 &&) = delete; + udt3(const udt3 &) = delete; + udt3 &operator=(udt3 &&) = delete; + udt3 &operator=(const udt3 &) = delete; + explicit udt3(int /*unused*/, const char * /*unused*/, std::nullptr_t /*unused*/) {} + ~udt3() = default; + }; + + result<int> a(5); + result<int> b(generic_code{errc::invalid_argument}); + std::cout << sizeof(a) << std::endl; // 32 bytes + if(false) // NOLINT + { + b.assume_value(); + a.assume_error(); + } +#ifndef BOOST_NO_EXCEPTIONS + try + { + b.value(); + std::cerr << "fail" << std::endl; + std::terminate(); + } + catch(const generic_error &e) + { + BOOST_CHECK(!strcmp(e.what(), b.error().message().c_str())); + } +#endif + static_assert(!std::is_default_constructible<decltype(a)>::value, ""); + static_assert(!std::is_nothrow_default_constructible<decltype(a)>::value, ""); + static_assert(!std::is_copy_constructible<decltype(a)>::value, ""); +// Quality of implementation of std::optional is poor :( +#ifndef TESTING_WG21_EXPERIMENTAL_RESULT + static_assert(!std::is_trivially_copy_constructible<decltype(a)>::value, ""); + static_assert(!std::is_nothrow_copy_constructible<decltype(a)>::value, ""); + static_assert(!std::is_copy_assignable<decltype(a)>::value, ""); + static_assert(!std::is_trivially_copy_assignable<decltype(a)>::value, ""); + static_assert(!std::is_nothrow_copy_assignable<decltype(a)>::value, ""); +#endif + static_assert(!std::is_trivially_destructible<decltype(a)>::value, ""); + static_assert(std::is_nothrow_destructible<decltype(a)>::value, ""); + + // Test void compiles + result<void> c(in_place_type<void>); + + // Test a standard udt compiles + result<udt> d(in_place_type<udt>); + static_assert(!std::is_default_constructible<decltype(d)>::value, ""); + static_assert(!std::is_nothrow_default_constructible<decltype(d)>::value, ""); + static_assert(!std::is_copy_constructible<decltype(d)>::value, ""); + static_assert(!std::is_trivially_copy_constructible<decltype(d)>::value, ""); + static_assert(!std::is_nothrow_copy_constructible<decltype(d)>::value, ""); + static_assert(!std::is_copy_assignable<decltype(d)>::value, ""); + static_assert(!std::is_trivially_copy_assignable<decltype(d)>::value, ""); + static_assert(!std::is_nothrow_copy_assignable<decltype(d)>::value, ""); + static_assert(std::is_move_assignable<decltype(d)>::value, ""); + static_assert(!std::is_trivially_move_assignable<decltype(d)>::value, ""); + static_assert(std::is_nothrow_move_assignable<decltype(d)>::value, ""); + static_assert(!std::is_trivially_destructible<decltype(d)>::value, ""); + static_assert(std::is_nothrow_destructible<decltype(d)>::value, ""); + + // Test a highly pathological udt compiles + result<udt2> e(in_place_type<udt2>, 5); + // result<udt2> e2(e); + static_assert(!std::is_default_constructible<decltype(e)>::value, ""); + static_assert(!std::is_nothrow_default_constructible<decltype(e)>::value, ""); + static_assert(!std::is_copy_constructible<decltype(e)>::value, ""); + static_assert(!std::is_trivially_copy_constructible<decltype(e)>::value, ""); + static_assert(!std::is_nothrow_copy_constructible<decltype(e)>::value, ""); + static_assert(!std::is_copy_assignable<decltype(e)>::value, ""); + static_assert(!std::is_trivially_copy_assignable<decltype(e)>::value, ""); + static_assert(!std::is_nothrow_copy_assignable<decltype(e)>::value, ""); + static_assert(!std::is_move_assignable<decltype(e)>::value, ""); + static_assert(!std::is_trivially_move_assignable<decltype(e)>::value, ""); + static_assert(!std::is_nothrow_move_assignable<decltype(e)>::value, ""); + + // Test a udt which can only be constructed in place compiles + result<udt3> g(in_place_type<udt3>, 5, static_cast<const char *>("niall"), nullptr); + // Does converting inplace construction also work? + result<udt3> h(5, static_cast<const char *>("niall"), nullptr); + result<udt3> i(generic_code{errc::not_enough_memory}); + BOOST_CHECK(h.has_value()); + BOOST_CHECK(i.has_error()); + } + + // Test direct use of error code enum works + { + constexpr result<int, errc, BOOST_OUTCOME_V2_NAMESPACE::policy::all_narrow> a(5), b(errc::invalid_argument); + static_assert(a.value() == 5, "a is not 5"); + static_assert(b.error() == errc::invalid_argument, "b is not errored"); + } + +#ifndef BOOST_NO_EXCEPTIONS + // Test payload facility + { + const char *niall = "niall"; + result<int, status_code_payload> b{payload{errc::invalid_argument, niall}}; + try + { + b.value(); + BOOST_CHECK(false); + } + catch(const payload_exception &e) + { + BOOST_CHECK(!strcmp(e.what(), niall)); + } + catch(...) + { + BOOST_CHECK(false); + } + } +#endif +} diff --git a/src/boost/libs/outcome/test/tests/experimental-p0709a.cpp b/src/boost/libs/outcome/test/tests/experimental-p0709a.cpp new file mode 100644 index 000000000..8823568ae --- /dev/null +++ b/src/boost/libs/outcome/test/tests/experimental-p0709a.cpp @@ -0,0 +1,169 @@ +/* Unit testing for outcomes +(C) 2017-2020 Niall Douglas <http://www.nedproductions.biz/> (7 commits) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#include <boost/outcome/experimental/status_result.hpp> + +#include <climits> // for INT_MAX +#include <cstdio> + +// status_code<erased<intptr_t>> +using error = BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::error; +// Outcome's result must be told when it is dealing with an erased status code +template <class T, class E> using result = BOOST_OUTCOME_V2_NAMESPACE::experimental::status_result<T, E, BOOST_OUTCOME_V2_NAMESPACE::policy::all_narrow>; + +enum class arithmetic_errc +{ + success, + divide_by_zero, + integer_divide_overflows, + not_integer_division +}; + +class _arithmetic_errc_domain; +using arithmetic_errc_error = BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code<_arithmetic_errc_domain>; + +class _arithmetic_errc_domain : public BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code_domain +{ + using _base = BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code_domain; + +public: + using value_type = arithmetic_errc; + + constexpr explicit _arithmetic_errc_domain(typename _base::unique_id_type id = 0x290f170194f0c6c7) noexcept : _base(id) {} + static inline constexpr const _arithmetic_errc_domain &get(); + + virtual _base::string_ref name() const noexcept override final // NOLINT + { + static string_ref v("arithmetic error domain"); + return v; // NOLINT + } + +protected: + virtual bool _do_failure(const BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code<void> &code) const noexcept override final // NOLINT + { + assert(code.domain() == *this); // NOLINT + const auto &c1 = static_cast<const arithmetic_errc_error &>(code); // NOLINT + return c1.value() != arithmetic_errc::success; + } + virtual bool _do_equivalent(const BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code<void> &, const BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code<void> &) const noexcept override final { return false; } // NOLINT + virtual BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::generic_code _generic_code(const BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code<void> &) const noexcept override final { return {}; } // NOLINT + virtual _base::string_ref _do_message(const BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code<void> &code) const noexcept override final // NOLINT + { + assert(code.domain() == *this); // NOLINT + const auto &c1 = static_cast<const arithmetic_errc_error &>(code); // NOLINT + switch(c1.value()) + { + case arithmetic_errc::success: + return _base::string_ref("success"); + case arithmetic_errc::divide_by_zero: + return _base::string_ref("divide by zero"); + case arithmetic_errc::integer_divide_overflows: + return _base::string_ref("integer divide overflows"); + case arithmetic_errc::not_integer_division: + return _base::string_ref("not integer division"); + } + return _base::string_ref("unknown"); + } + BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN virtual void _do_throw_exception(const BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code<void> &) const override final { abort(); } // NOLINT +}; + +constexpr _arithmetic_errc_domain arithmetic_errc_domain; +inline constexpr const _arithmetic_errc_domain &_arithmetic_errc_domain::get() +{ + return arithmetic_errc_domain; +} + + +// Tell status code about the available implicit conversion +inline arithmetic_errc_error make_status_code(arithmetic_errc e) +{ + return arithmetic_errc_error(BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::in_place, e); +} + +BOOST_OUTCOME_V2_NAMESPACE_BEGIN +namespace trait +{ + // Tell Outcome that arithmetic_errc is convertible into std::error + template <> struct is_error_type_enum<error, arithmetic_errc> + { + static constexpr bool value = true; + }; +} +BOOST_OUTCOME_V2_NAMESPACE_END +// And tell Outcome how to perform the implicit conversion +inline error make_error_code(arithmetic_errc e) +{ + return arithmetic_errc_error(BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::in_place, e); +} + + +result<int, error> safe_divide(int i, int j) +{ + if(j == 0) + { + return arithmetic_errc::divide_by_zero; + } + if(i == INT_MIN && j == -1) + { + return arithmetic_errc::integer_divide_overflows; + } + if(i % j != 0) + { + return arithmetic_errc::not_integer_division; + } + return i / j; +} + +int caller2(int i, int j) +{ + auto r = safe_divide(i, j); + if(r) + { + return r.value(); + } + if(r.error() == arithmetic_errc::divide_by_zero) + { + return 0; + } + if(r.error() == arithmetic_errc::not_integer_division) + { + return i / j; // ignore + } + if(r.error() == arithmetic_errc::integer_divide_overflows) + { + return INT_MIN; + } + return 0; +} + +int main() +{ + printf("%d\n", caller2(5, 6)); // NOLINT + return 0; +} diff --git a/src/boost/libs/outcome/test/tests/fileopen.cpp b/src/boost/libs/outcome/test/tests/fileopen.cpp new file mode 100644 index 000000000..f2634d4fd --- /dev/null +++ b/src/boost/libs/outcome/test/tests/fileopen.cpp @@ -0,0 +1,87 @@ +/* Unit testing for outcomes +(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (7 commits) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#define _CRT_SECURE_NO_WARNINGS + +#include <boost/outcome.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +#ifndef BOOST_NO_EXCEPTIONS + +#ifdef _MSC_VER +#define BOOST_OUTCOME_POSIX_OPEN ::_open +#include <io.h> +#else +#define BOOST_OUTCOME_POSIX_OPEN ::open +#include <fcntl.h> +#endif + +BOOST_OUTCOME_AUTO_TEST_CASE(works_outcome_fileopen, "Tests that the outcome semantically represents opening a file") +{ + using namespace BOOST_OUTCOME_V2_NAMESPACE; + + //! [file_open_example] + auto openfile = [](std::string path) noexcept->outcome<int> + { + int fd; + do + { + fd = BOOST_OUTCOME_POSIX_OPEN(path.c_str(), 0); // NOLINT + } while(-1 == fd && EINTR == errno); + try + { + if(-1 == fd) + { + int code = errno; + // If a temporary failure, this is an expected unexpected outcome + if(EBUSY == code || EISDIR == code || ELOOP == code || ENOENT == code || ENOTDIR == code || EPERM == code || EACCES == code) + { + return boost::system::error_code(code, boost::system::generic_category()); + } + // If a non-temporary failure, this is an unexpected outcome + return boost::copy_exception(boost::system::system_error(code, boost::system::generic_category(), strerror(code))); + } + return fd; + } + catch(...) + { + // Any exception thrown is truly unexpected + return boost::current_exception(); + } + }; + auto a = openfile("shouldneverexistnotever"); + BOOST_CHECK(!a); + BOOST_CHECK(!a.has_value()); + BOOST_CHECK(!a.has_exception()); + BOOST_CHECK(a.has_error()); + BOOST_CHECK(a.error() == boost::system::error_code(ENOENT, boost::system::generic_category())); + //! [file_open_example] +} +#endif diff --git a/src/boost/libs/outcome/test/tests/hooks.cpp b/src/boost/libs/outcome/test/tests/hooks.cpp new file mode 100644 index 000000000..857113cde --- /dev/null +++ b/src/boost/libs/outcome/test/tests/hooks.cpp @@ -0,0 +1,114 @@ +/* Unit testing for outcomes +(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (14 commits) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#define _CRT_SECURE_NO_WARNINGS + +#include <boost/outcome/outcome.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +#include <iostream> + +namespace hook_test +{ + using BOOST_OUTCOME_V2_NAMESPACE::in_place_type; + // Use static storage to convey extended error info from result construction to outcome conversion + static char extended_error_info[256]; + + // Use the error_code type as the ADL bridge for the hooks by creating a type here + struct error_code : public boost::system::error_code + { + using boost::system::error_code::error_code; + error_code() = default; + error_code(boost::system::error_code ec) // NOLINT + : boost::system::error_code(ec) + { + } + }; + // Localise result to using the local error_code so this namespace gets looked up for the hooks + template <class R> using result = BOOST_OUTCOME_V2_NAMESPACE::result<R, error_code>; + // Specialise the result construction hook for our localised result + template <class U> constexpr inline void hook_result_construction(result<int> *res, U && /*unused*/) noexcept + { + // Write the value in the result into the static storage + snprintf(extended_error_info, sizeof(extended_error_info), "%d", res->assume_value()); // NOLINT + } + template <class U> constexpr inline void hook_result_construction(result<std::string> *res, U && /*unused*/) noexcept + { + // Write the value in the result into the static storage + snprintf(extended_error_info, sizeof(extended_error_info), "%s", res->assume_value().c_str()); // NOLINT + } +} // namespace hook_test + +BOOST_OUTCOME_AUTO_TEST_CASE(works_result_hooks, "Tests that you can hook result's construction") +{ + using namespace hook_test; + result<int> a(5); + BOOST_CHECK(!strcmp(extended_error_info, "5")); // NOLINT + result<std::string> b("niall"); + BOOST_CHECK(!strcmp(extended_error_info, "niall")); // NOLINT +} + +//! [extended_error_coding2] +namespace hook_test +{ + // Localise outcome to using the local error_code so this namespace gets looked up for the hooks + template <class R> using outcome = BOOST_OUTCOME_V2_NAMESPACE::outcome<R, error_code, std::string>; + + // Specialise the outcome copy and move conversion hook for our localised result + template <class T, class U> constexpr inline void hook_outcome_copy_construction(outcome<T> *res, const result<U> & /*unused*/) noexcept + { + // when copy constructing from a result<T>, place extended_error_coding::extended_error_info into the payload + std::cout << "hook_outcome_copy_construction fires" << std::endl; + BOOST_OUTCOME_V2_NAMESPACE::hooks::override_outcome_exception(res, extended_error_info); + } + template <class T, class U> constexpr inline void hook_outcome_move_construction(outcome<T> *res, result<U> && /*unused*/) noexcept + { + // when move constructing from a result<T>, place extended_error_coding::extended_error_info into the payload + std::cout << "hook_outcome_move_construction fires" << std::endl; + BOOST_OUTCOME_V2_NAMESPACE::hooks::override_outcome_exception(res, extended_error_info); + } +} // namespace hook_test + +BOOST_OUTCOME_AUTO_TEST_CASE(works_outcome_hooks, "Tests that you can hook outcome's conversion from a result") +{ + using namespace hook_test; + outcome<int> a(result<int>(5)); + BOOST_REQUIRE(a.has_exception()); // NOLINT + BOOST_CHECK(a.exception() == "5"); + outcome<std::string> b(result<std::string>("niall")); + BOOST_CHECK(b.exception() == "niall"); + + // Make sure hook does not fire for any other kind of outcome copy or move, only when converting from our custom result only + outcome<int> c(5); + outcome<long> d(c); // can't be the same type as source, else copy elision takes place and no ADL hook calling + BOOST_CHECK(!d.has_exception()); + outcome<int> e(BOOST_OUTCOME_V2_NAMESPACE::result<int>(5)); + BOOST_CHECK(!e.has_exception()); +} diff --git a/src/boost/libs/outcome/test/tests/issue0007.cpp b/src/boost/libs/outcome/test/tests/issue0007.cpp new file mode 100644 index 000000000..d890c333e --- /dev/null +++ b/src/boost/libs/outcome/test/tests/issue0007.cpp @@ -0,0 +1,81 @@ +/* Unit testing for outcomes +(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (5 commits) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#include <boost/outcome/outcome.hpp> +#include <boost/outcome/try.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +BOOST_OUTCOME_AUTO_TEST_CASE(issues_0007_test, "BOOST_OUTCOME_TRYV(expr) in a function whose return outcome's type has no default constructor fails to compile") +{ + using namespace BOOST_OUTCOME_V2_NAMESPACE; + struct udt // NOLINT + { + explicit udt(int /*unused*/) {} + // udt() = delete; + udt(const udt &) = default; + udt(udt &&) = default; + }; + { + auto f = []() -> result<udt> { + auto g = [] { return result<int>(5); }; + /* This fails because BOOST_OUTCOME_TRYV() returns a result<void> + which if it were valued void, would implicitly convert into a + default constructed udt which is not possible, hence the compile error. + */ + BOOST_OUTCOME_TRYV(g()); + return udt(5); + }; + (void) f(); + } + { + auto f = []() -> outcome<udt> { + auto g = [] { return outcome<int>(5); }; + /* This fails because BOOST_OUTCOME_TRYV() returns a result<void> + which if it were valued void, would implicitly convert into a + default constructed udt which is not possible, hence the compile error. + */ + BOOST_OUTCOME_TRYV(g()); + return udt(5); + }; + (void) f(); + } + { + auto f = []() -> outcome<udt> { + auto g = [] { return result<int>(5); }; + /* This fails because BOOST_OUTCOME_TRYV() returns a result<void> + which if it were valued void, would implicitly convert into a + default constructed udt which is not possible, hence the compile error. + */ + BOOST_OUTCOME_TRYV(g()); + return udt(5); + }; + (void) f(); + } +} diff --git a/src/boost/libs/outcome/test/tests/issue0009.cpp b/src/boost/libs/outcome/test/tests/issue0009.cpp new file mode 100644 index 000000000..7a61cfc92 --- /dev/null +++ b/src/boost/libs/outcome/test/tests/issue0009.cpp @@ -0,0 +1,52 @@ +/* Unit testing for outcomes +(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (5 commits) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#include <boost/outcome/outcome.hpp> +#include <boost/outcome/try.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +BOOST_OUTCOME_AUTO_TEST_CASE(issues_0009_test, "Alternative TRY macros?") +{ +#ifdef BOOST_OUTCOME_TRYX + using namespace BOOST_OUTCOME_V2_NAMESPACE; + struct udt // NOLINT + { + explicit udt(int /*unused*/) {} + // udt() = delete; + udt(const udt &) = default; + udt(udt &&) = default; + }; + auto f = []() -> result<udt> { + auto g = [] { return result<int>(5); }; + return udt(BOOST_OUTCOME_TRYX(g())); + }; + (void) f(); +#endif +} diff --git a/src/boost/libs/outcome/test/tests/issue0010.cpp b/src/boost/libs/outcome/test/tests/issue0010.cpp new file mode 100644 index 000000000..84a897773 --- /dev/null +++ b/src/boost/libs/outcome/test/tests/issue0010.cpp @@ -0,0 +1,88 @@ +/* Unit testing for outcomes +(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (9 commits) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#include <boost/outcome/outcome.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +BOOST_OUTCOME_AUTO_TEST_CASE(issues_0010_test, "Expected's operator->(), operator*() and .error() throw exceptions when they should not") +{ + using namespace BOOST_OUTCOME_V2_NAMESPACE; + const char *a = "hi", *b = "bye"; + struct udt1 // NOLINT + { + const char *_v{nullptr}; + udt1() = default; + constexpr explicit udt1(const char *v) noexcept : _v(v) {} + constexpr udt1(udt1 &&o) noexcept : _v(o._v) { o._v = nullptr; } + udt1(const udt1 &) = default; + constexpr udt1 &operator=(udt1 &&o) noexcept + { + _v = o._v; + o._v = nullptr; + return *this; + } + udt1 &operator=(const udt1 &) = delete; + constexpr const char *operator*() const noexcept { return _v; } + }; + struct udt2 // NOLINT + { + const char *_v{nullptr}; + udt2() = default; + constexpr explicit udt2(const char *v) noexcept : _v(v) {} + constexpr udt2(udt2 &&o) noexcept : _v(o._v) { o._v = nullptr; } + udt2(const udt2 &) = default; + constexpr udt2 &operator=(udt2 &&o) noexcept + { + _v = o._v; + o._v = nullptr; + return *this; + } + udt1 &operator=(const udt1 &) = delete; + constexpr const char *operator*() const noexcept { return _v; } + }; + result<udt1, udt2> p(udt1{a}); + result<udt1, udt2> n(udt2{b}); + // State check + BOOST_CHECK(p.has_value()); + BOOST_CHECK(!n.has_value()); + // These should behave as expected (!) + // BOOST_CHECK_NO_THROW(p.value()); + // BOOST_CHECK_NO_THROW(n.value()); + // And state is not destroyed + BOOST_CHECK(p.has_value() && *p.assume_value() == a); + BOOST_CHECK(!n.has_value() && *n.assume_error() == b); + // LEWG Expected provides rvalue ref semantics for operator*(), error() and error_or() + udt1 a1(std::move(p.assume_value())); + BOOST_CHECK(*a1 == a); + BOOST_CHECK(*p.assume_value() == nullptr); + udt2 e2(std::move(n).assume_error()); + BOOST_CHECK(*e2 == b); + BOOST_CHECK(*n.assume_error() == nullptr); // NOLINT +} diff --git a/src/boost/libs/outcome/test/tests/issue0012.cpp b/src/boost/libs/outcome/test/tests/issue0012.cpp new file mode 100644 index 000000000..ff5d3c83e --- /dev/null +++ b/src/boost/libs/outcome/test/tests/issue0012.cpp @@ -0,0 +1,59 @@ +/* Unit testing for outcomes +(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (5 commits) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#include <boost/outcome/outcome.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +BOOST_OUTCOME_AUTO_TEST_CASE(issues_0012_test, "outcome's copy assignment gets instantiated even when type T cannot be copied") +{ + using namespace BOOST_OUTCOME_V2_NAMESPACE; + const char *s = "hi"; + struct udt // NOLINT + { + const char *_v{nullptr}; + udt() = default; + constexpr explicit udt(const char *v) noexcept : _v(v) {} + constexpr udt(udt &&o) noexcept : _v(o._v) { o._v = nullptr; } + udt(const udt &) = delete; + constexpr udt &operator=(udt &&o) noexcept + { + _v = o._v; + o._v = nullptr; + return *this; + } + udt &operator=(const udt &) = delete; + constexpr const char *operator*() const noexcept { return _v; } + }; + static_assert(std::is_move_constructible<outcome<udt>>::value, "expected<udt> is not move constructible!"); + static_assert(!std::is_copy_constructible<outcome<udt>>::value, "expected<udt> is copy constructible!"); + outcome<udt> p(udt{s}), n(boost::system::error_code(ENOMEM, boost::system::generic_category())); + n = boost::system::error_code(EINVAL, boost::system::generic_category()); + BOOST_CHECK(n.error().value() == EINVAL); +} diff --git a/src/boost/libs/outcome/test/tests/issue0016.cpp b/src/boost/libs/outcome/test/tests/issue0016.cpp new file mode 100644 index 000000000..ddf5dd158 --- /dev/null +++ b/src/boost/libs/outcome/test/tests/issue0016.cpp @@ -0,0 +1,56 @@ +/* Unit testing for outcomes +(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (5 commits) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#include <boost/outcome/outcome.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +BOOST_OUTCOME_AUTO_TEST_CASE(issues_0016_test, "Default constructor of T is sometimes compiled when T has no default constructor") +{ + using namespace BOOST_OUTCOME_V2_NAMESPACE; + struct udt + { + const char *_v{nullptr}; + udt() = delete; + constexpr explicit udt(const char *v) noexcept : _v(v) {} + constexpr udt(udt &&o) noexcept : _v(o._v) { o._v = nullptr; } + udt(const udt &) = delete; + constexpr udt &operator=(udt &&o) noexcept + { + _v = o._v; + o._v = nullptr; + return *this; + } + udt &operator=(const udt &) = delete; + ~udt() = default; + constexpr const char *operator*() const noexcept { return _v; } + }; + result<udt> n(boost::system::error_code(ENOMEM, boost::system::generic_category())); + (void) n; +} diff --git a/src/boost/libs/outcome/test/tests/issue0059.cpp b/src/boost/libs/outcome/test/tests/issue0059.cpp new file mode 100644 index 000000000..867ec6670 --- /dev/null +++ b/src/boost/libs/outcome/test/tests/issue0059.cpp @@ -0,0 +1,60 @@ +/* Unit testing for outcomes +(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (8 commits) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#include <boost/outcome/result.hpp> +#include <boost/outcome/try.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +BOOST_OUTCOME_AUTO_TEST_CASE(issues_0059_test, "result<NonMovable> supported?") +{ +#if defined(_MSC_VER) || __cplusplus >= 201700 + using namespace BOOST_OUTCOME_V2_NAMESPACE; + struct udt + { + const char *_v{nullptr}; + udt() = delete; + constexpr udt(const char *v) noexcept : _v(v) {} // NOLINT + udt(udt &&o) = delete; + udt(const udt &) = delete; + udt &operator=(udt &&o) = delete; + udt &operator=(const udt &) = delete; + ~udt() = default; + constexpr const char *operator*() const noexcept { return _v; } + }; + const char *niall = "niall"; + auto f = [niall]() -> result<void> { + auto g = [niall]() -> result<udt> { return {niall}; }; + BOOST_OUTCOME_TRY(v, g()); // this must never copy nor move + BOOST_CHECK(*v == niall); + return success(); + }; + (void) f(); +#endif +} diff --git a/src/boost/libs/outcome/test/tests/issue0061.cpp b/src/boost/libs/outcome/test/tests/issue0061.cpp new file mode 100644 index 000000000..aab9a3bff --- /dev/null +++ b/src/boost/libs/outcome/test/tests/issue0061.cpp @@ -0,0 +1,128 @@ +/* Unit testing for outcomes +(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (6 commits) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#include <boost/outcome/outcome.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +BOOST_OUTCOME_AUTO_TEST_CASE(issues_0061_result, "result<T1, E1> does not compare to incompatible result<T2, E2>") +{ + using namespace BOOST_OUTCOME_V2_NAMESPACE; + struct udt1 + { + const char *_v{nullptr}; + udt1() = default; + constexpr udt1(const char *v) noexcept : _v(v) {} // NOLINT + udt1(udt1 &&o) = delete; + udt1(const udt1 &) = delete; + udt1 &operator=(udt1 &&o) = delete; + udt1 &operator=(const udt1 &) = delete; + ~udt1() = default; + constexpr const char *operator*() const noexcept { return _v; } + }; + struct udt2 + { + const char *_v{nullptr}; + udt2() = default; + constexpr explicit udt2(const char *v) noexcept : _v(v) {} + udt2(udt2 &&o) = delete; + udt2(const udt2 &) = delete; + udt2 &operator=(udt2 &&o) = delete; + udt2 &operator=(const udt2 &) = delete; + ~udt2() = default; + constexpr const char *operator*() const noexcept { return _v; } + bool operator==(const udt1 &o) const noexcept { return _v == *o; } + bool operator!=(const udt1 &o) const noexcept { return _v != *o; } + }; + using result1 = result<int, udt1>; + using result2 = result<int, udt2>; + + result1 a(5); + result2 b(5); + BOOST_CHECK(b == a); // udt2 will compare to udt1 + BOOST_CHECK(!(b != a)); // udt2 will compare to udt1 + + result<void> c = success(); + result<void> d = success(); + BOOST_CHECK(c == d); + BOOST_CHECK(!(c != d)); + + BOOST_CHECK(a == success()); + BOOST_CHECK(success() == a); + BOOST_CHECK(b != failure("foo")); + BOOST_CHECK(failure("foo") != b); +} + +BOOST_OUTCOME_AUTO_TEST_CASE(issues_0061_outcome, "outcome<T1, E1, P1> does not compare to incompatible outcome<T2, E2, P2>") +{ + using namespace BOOST_OUTCOME_V2_NAMESPACE; + struct udt1 + { + const char *_v{nullptr}; + udt1() = default; + constexpr udt1(const char *v) noexcept : _v(v) {} // NOLINT + udt1(udt1 &&o) = delete; + udt1(const udt1 &) = delete; + udt1 &operator=(udt1 &&o) = delete; + udt1 &operator=(const udt1 &) = delete; + ~udt1() = default; + constexpr const char *operator*() const noexcept { return _v; } + }; + struct udt2 + { + const char *_v{nullptr}; + udt2() = default; + constexpr explicit udt2(const char *v) noexcept : _v(v) {} + udt2(udt2 &&o) = delete; + udt2(const udt2 &) = delete; + udt2 &operator=(udt2 &&o) = delete; + udt2 &operator=(const udt2 &) = delete; + ~udt2() = default; + constexpr const char *operator*() const noexcept { return _v; } + bool operator==(const udt1 &o) const noexcept { return _v == *o; } + bool operator!=(const udt1 &o) const noexcept { return _v != *o; } + }; + using outcome1 = outcome<int, udt1>; + using outcome2 = outcome<int, udt2>; + + outcome1 a(5), _a(6); + outcome2 b(5); + BOOST_CHECK(b == a); // udt2 will compare to udt1 + BOOST_CHECK(!(b != a)); // udt2 will compare to udt1 + + outcome<void> c = success(); + outcome<void> d = success(); + BOOST_CHECK(c == d); + BOOST_CHECK(!(c != d)); + + BOOST_CHECK(a == success()); + BOOST_CHECK(success() == a); + BOOST_CHECK(b != failure("foo")); + BOOST_CHECK(failure("foo") != b); +} diff --git a/src/boost/libs/outcome/test/tests/issue0064.cpp b/src/boost/libs/outcome/test/tests/issue0064.cpp new file mode 100644 index 000000000..6dbdcd91c --- /dev/null +++ b/src/boost/libs/outcome/test/tests/issue0064.cpp @@ -0,0 +1,50 @@ +/* Unit testing for outcomes +(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (4 commits) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#include <boost/outcome/iostream_support.hpp> +#include <boost/outcome/outcome.hpp> +#include <boost/outcome/try.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +BOOST_OUTCOME_AUTO_TEST_CASE(issues_0064_outcome, "BOOST_OUTCOME_TRY on excepted outcome is propagating a null error rather than just an exception") +{ +#ifndef BOOST_NO_EXCEPTIONS + using namespace BOOST_OUTCOME_V2_NAMESPACE; + auto f = []() -> outcome<int> { + auto h = []() -> outcome<int> { return boost::copy_exception(std::runtime_error("hello")); }; + BOOST_OUTCOME_TRY((h())); + return 0; + }(); + std::cout << print(f) << std::endl; + BOOST_CHECK(!f.has_value()); + BOOST_CHECK(!f.has_error()); + BOOST_CHECK(f.has_exception()); +#endif +} diff --git a/src/boost/libs/outcome/test/tests/issue0065.cpp b/src/boost/libs/outcome/test/tests/issue0065.cpp new file mode 100644 index 000000000..c537a38a7 --- /dev/null +++ b/src/boost/libs/outcome/test/tests/issue0065.cpp @@ -0,0 +1,66 @@ +/* Unit testing for outcomes +(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (3 commits) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#include <boost/outcome/outcome.hpp> +#include <boost/outcome/try.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +BOOST_OUTCOME_AUTO_TEST_CASE(issues_0065_outcome, "BOOST_OUTCOME_TRY does not preserve the exception_ptr") +{ +#ifndef BOOST_NO_EXCEPTIONS + using namespace BOOST_OUTCOME_V2_NAMESPACE; + auto g = []() -> outcome<int> { + auto f = []() -> outcome<int> { + try + { + throw std::runtime_error{"XXX"}; + } + catch(...) + { + return boost::current_exception(); + } + }; + BOOST_OUTCOME_TRY(ans, (f())); + return ans; + }; + outcome<int> o = g(); + BOOST_CHECK(!o); + BOOST_CHECK(o.has_exception()); + try + { + o.value(); + BOOST_CHECK(false); + } + catch(const std::runtime_error &e) + { + BOOST_CHECK(!strcmp(e.what(), "XXX")); + } +#endif +} diff --git a/src/boost/libs/outcome/test/tests/issue0071.cpp b/src/boost/libs/outcome/test/tests/issue0071.cpp new file mode 100644 index 000000000..333fb2088 --- /dev/null +++ b/src/boost/libs/outcome/test/tests/issue0071.cpp @@ -0,0 +1,45 @@ +/* Unit testing for outcomes +(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (4 commits) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#include <boost/outcome/result.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +BOOST_OUTCOME_AUTO_TEST_CASE(issues_0071_outcome, "Implicit construction is over eager") +{ + using namespace BOOST_OUTCOME_V2_NAMESPACE; + struct udt + { + int v; + explicit udt(int a) + : v(a){}; + }; + result<udt> m = udt{5}; + BOOST_CHECK(m.value().v == 5); +} diff --git a/src/boost/libs/outcome/test/tests/issue0095.cpp b/src/boost/libs/outcome/test/tests/issue0095.cpp new file mode 100644 index 000000000..c1ed1d460 --- /dev/null +++ b/src/boost/libs/outcome/test/tests/issue0095.cpp @@ -0,0 +1,58 @@ +/* Unit testing for outcomes +(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (6 commits) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#include <boost/outcome/result.hpp> +#include <boost/outcome/try.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +namespace issue0095 +{ + namespace out = BOOST_OUTCOME_V2_NAMESPACE; + + struct E + { + }; + // struct F : E {}; + struct F + { + operator E() const { return E{}; } // NOLINT + }; + + out::result<int, F> f() { return F{}; } + out::result<int, E> e() + { + BOOST_OUTCOME_TRY(i, (f())); + return i; + } +} // namespace issue0095 +BOOST_OUTCOME_AUTO_TEST_CASE(issues_0095_outcome, "operator conversions on E type cause TRY to fail") +{ + BOOST_CHECK(issue0095::e().has_error()); +} diff --git a/src/boost/libs/outcome/test/tests/issue0115.cpp b/src/boost/libs/outcome/test/tests/issue0115.cpp new file mode 100644 index 000000000..17d852274 --- /dev/null +++ b/src/boost/libs/outcome/test/tests/issue0115.cpp @@ -0,0 +1,57 @@ +/* Unit testing for outcomes +(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (1 commit) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#include <boost/outcome/outcome.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +BOOST_OUTCOME_AUTO_TEST_CASE(issues_0115_outcome, "Initialization from `failure_type` drops default-constructed values") +{ + namespace out = BOOST_OUTCOME_V2_NAMESPACE; + + out::outcome<int> o1 = boost::system::error_code{}; + BOOST_CHECK(o1.has_error()); + BOOST_CHECK(!o1.has_exception()); + + out::outcome<int> o2 = out::failure(boost::system::error_code{}); + BOOST_CHECK(o2.has_error()); + BOOST_CHECK(!o2.has_exception()); + + out::outcome<int> o3(boost::system::error_code{}, boost::exception_ptr{}); + BOOST_CHECK(o3.has_error()); + BOOST_CHECK(o3.has_exception()); + + out::outcome<int> o4 = out::failure(boost::system::error_code{}, boost::exception_ptr{}); + BOOST_CHECK(o4.has_error()); + BOOST_CHECK(o4.has_exception()); + + out::outcome<int> o5 = out::failure(boost::exception_ptr{}); + BOOST_CHECK(!o5.has_error()); + BOOST_CHECK(o5.has_exception()); +} diff --git a/src/boost/libs/outcome/test/tests/issue0116.cpp b/src/boost/libs/outcome/test/tests/issue0116.cpp new file mode 100644 index 000000000..168c3e5c4 --- /dev/null +++ b/src/boost/libs/outcome/test/tests/issue0116.cpp @@ -0,0 +1,45 @@ +/* Unit testing for outcomes +(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (2 commits) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#include <boost/outcome/outcome.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +BOOST_OUTCOME_AUTO_TEST_CASE(issues_0116_outcome, "Bad implementation of outcome::operator==") +{ + namespace out = BOOST_OUTCOME_V2_NAMESPACE; + + out::outcome<int> o1 = 1; + BOOST_CHECK(!o1.has_error()); + + out::outcome<int> o2 = out::failure(boost::system::error_code{EINVAL, boost::system::generic_category()}); + BOOST_CHECK(o2.has_error()); + + BOOST_CHECK(o1 != o2); +} diff --git a/src/boost/libs/outcome/test/tests/issue0140.cpp b/src/boost/libs/outcome/test/tests/issue0140.cpp new file mode 100644 index 000000000..bb86f0619 --- /dev/null +++ b/src/boost/libs/outcome/test/tests/issue0140.cpp @@ -0,0 +1,96 @@ +/* Unit testing for outcomes +(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (2 commits) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#include <boost/outcome/outcome.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +BOOST_OUTCOME_AUTO_TEST_CASE(issues_0140_result, "Construction of non copy constructible value_type fails to not compile") +{ + namespace out = BOOST_OUTCOME_V2_NAMESPACE; + + enum op + { + constructed, + moved, + copied + }; + struct NotCopyMoveConstructible + { + op v{op::constructed}; + NotCopyMoveConstructible() = default; + NotCopyMoveConstructible(const NotCopyMoveConstructible &o) = delete; + NotCopyMoveConstructible(NotCopyMoveConstructible &&) = delete; + NotCopyMoveConstructible &operator=(const NotCopyMoveConstructible &) = delete; + NotCopyMoveConstructible &operator=(NotCopyMoveConstructible &&) = delete; + ~NotCopyMoveConstructible() = default; + }; + struct NotMoveConstructible + { + op v{op::constructed}; + NotMoveConstructible() = default; + NotMoveConstructible(const NotMoveConstructible & /*unused*/) + : v(op::copied) + { + } + NotMoveConstructible(NotMoveConstructible &&) = delete; + NotMoveConstructible &operator=(const NotMoveConstructible &) = delete; + NotMoveConstructible &operator=(NotMoveConstructible &&) = delete; + ~NotMoveConstructible() = default; + }; + struct NotCopyConstructible + { + op v{op::constructed}; + NotCopyConstructible() = default; + NotCopyConstructible(NotCopyConstructible && /*unused*/) noexcept : v(op::moved) {} + NotCopyConstructible(const NotCopyConstructible & /*unused*/) = delete; + NotCopyConstructible &operator=(const NotCopyConstructible &) = delete; + NotCopyConstructible &operator=(NotCopyConstructible &&) = delete; + ~NotCopyConstructible() = default; + }; + + // Uncopyable and immovable items should be neither copyable nor moveable + static_assert(!std::is_copy_constructible<out::result<NotCopyMoveConstructible>>::value, "result<NotCopyMoveConstructible> is copy constructible!"); + static_assert(!std::is_move_constructible<out::result<NotCopyMoveConstructible>>::value, "result<NotCopyMoveConstructible> is move constructible!"); + static_assert(!std::is_convertible<const NotCopyMoveConstructible &, NotCopyMoveConstructible>::value, ""); + static_assert(!std::is_convertible<NotCopyMoveConstructible &&, NotCopyMoveConstructible>::value, ""); + static_assert(!std::is_constructible<out::result<NotCopyMoveConstructible>, const NotCopyMoveConstructible &>::value, "result<NotCopyMoveConstructible> is constructible from const NotCopyMoveConstructible&!"); + static_assert(!std::is_constructible<out::result<NotCopyMoveConstructible>, NotCopyMoveConstructible &&>::value, "result<NotCopyMoveConstructible> is constructible from NotCopyMoveConstructible&&!"); + + // Immovable items should fall back to copy + static_assert(!std::is_move_constructible<NotMoveConstructible>::value, "NotMoveConstructible is move constructible!"); + static_assert(std::is_move_constructible<out::result<NotMoveConstructible>>::value, "result<NotMoveConstructible> is not move constructible!"); + static_assert(std::is_constructible<out::result<NotMoveConstructible>, const NotMoveConstructible &>::value, "result<NotMoveConstructible> is not constructible from NotMoveConstructible&&!"); + + // Uncopyable items should never move (this was the bug report) + static_assert(!std::is_copy_constructible<out::result<NotCopyConstructible>>::value, "result<NotCopyConstructible> is copy constructible!"); + static_assert(!std::is_constructible<out::result<NotCopyConstructible>, const NotCopyConstructible &>::value, "result<NotCopyConstructible> is constructible from const NotCopyConstructible&!"); + + BOOST_CHECK(true); +} diff --git a/src/boost/libs/outcome/test/tests/issue0182.cpp b/src/boost/libs/outcome/test/tests/issue0182.cpp new file mode 100644 index 000000000..7bf06d424 --- /dev/null +++ b/src/boost/libs/outcome/test/tests/issue0182.cpp @@ -0,0 +1,42 @@ +/* Unit testing for outcomes +(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (1 commit) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#include <boost/outcome/outcome.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +BOOST_OUTCOME_AUTO_TEST_CASE(issues_0189_test, "result<void, int>.value() compiles without tripping fail_to_compile_observers") +{ + namespace outcome = BOOST_OUTCOME_V2_NAMESPACE; + static_assert(!outcome::trait::is_error_code_available<int>::value, "int is clearly not a source for make_error_code()"); + static_assert(!outcome::trait::is_exception_ptr_available<int>::value, "int is clearly not a source for make_exception_ptr()"); + //outcome::result<void, int> r(5); + //r.value(); + BOOST_CHECK(true); +} diff --git a/src/boost/libs/outcome/test/tests/issue0203.cpp b/src/boost/libs/outcome/test/tests/issue0203.cpp new file mode 100644 index 000000000..800fa8373 --- /dev/null +++ b/src/boost/libs/outcome/test/tests/issue0203.cpp @@ -0,0 +1,103 @@ +/* Unit testing for outcomes +(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (1 commit) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#include <boost/outcome/std_result.hpp> +#include <boost/outcome/try.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +namespace outcome = BOOST_OUTCOME_V2_NAMESPACE; + +enum class error +{ + test, + abcde +}; + +class error_category_impl : public std::error_category +{ +public: + const char *name() const noexcept override { return "test"; } + + std::string message(int code) const noexcept override + { + switch(static_cast<error>(code)) + { + case error::test: + return "test"; + case error::abcde: + return "abcde"; + } + return "unknown"; + } +}; +const std::error_category &error_category() noexcept +{ + static error_category_impl instance; + return instance; +} + +boost::system::error_code make_error_code(error error) noexcept +{ + return {static_cast<int>(error), error_category()}; +} + +namespace std +{ + template <> struct is_error_code_enum<error> : true_type + { + }; +} // namespace std + +template <typename T> using enum_result = outcome::basic_result<T, error, outcome::policy::default_policy<T, error, void>>; + +enum_result<int> test() +{ + return 5; +} + +outcome::std_result<int> abc() +{ + static_assert(std::is_error_code_enum<error>::value, "custom enum is not marked convertible to error code"); + static_assert(std::is_constructible<boost::system::error_code, error>::value, "error code is not explicitly constructible from custom enum"); + static_assert(std::is_convertible<error, boost::system::error_code>::value, "error code is not implicitly constructible from custom enum"); + boost::system::error_code ec = error::test; // custom enum is definitely convertible to error code + BOOST_OUTCOME_TRY(test()); // hence this should compile, as implicit conversions work here + (void) ec; + + // But explicit conversions are required between dissimilar basic_result, implicit conversions are disabled + static_assert(std::is_constructible<outcome::std_result<int>, enum_result<int>>::value, "basic_result with error code is not explicitly constructible from basic_result with custom enum"); + static_assert(!std::is_convertible<enum_result<int>, outcome::std_result<int>>::value, "basic_result with error code is implicitly constructible from basic_result with custom enum"); + return 5; +} + +BOOST_OUTCOME_AUTO_TEST_CASE(issues_0203_test, "enum convertible to error code works as designed") +{ + BOOST_CHECK(abc().value() == 5); +} diff --git a/src/boost/libs/outcome/test/tests/issue0210.cpp b/src/boost/libs/outcome/test/tests/issue0210.cpp new file mode 100644 index 000000000..0ac1b759a --- /dev/null +++ b/src/boost/libs/outcome/test/tests/issue0210.cpp @@ -0,0 +1,78 @@ +/* Unit testing for outcomes +(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (1 commit) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#include <boost/outcome/outcome.hpp> +#include <boost/outcome/try.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +namespace issues210 +{ + namespace outcome = BOOST_OUTCOME_V2_NAMESPACE; + + struct error + { + boost::system::error_code code; + }; + + // say that my custom error code type is error code compatible + inline boost::system::error_code make_error_code(error error) noexcept { return error.code; } + + template <typename T> using custom_result = outcome::basic_result<T, error, outcome::policy::default_policy<T, error, void>>; + + // source of custom result type with error code compatible error type + inline custom_result<int> funcA(int x) { return x; } + + // Is the custom result type explicitly constructible to an ordinary result type? + inline outcome::result<int> funcB(int x) { return outcome::result<int>(funcA(x)); } + + // Does the custom result type TRY-convert to an ordinary result type? + inline outcome::result<int> func1(int x) + { + BOOST_OUTCOME_TRY(y, funcA(x)); + return funcB(y); + } + + // Is the custom result type explicitly constructible to an ordinary outcome type? + inline outcome::outcome<int> funcC(int x) { return outcome::outcome<int>(funcA(x)); } + + // Does the custom result type TRY-convert to an ordinary outcome type? + inline outcome::outcome<int> func2(int x) + { + BOOST_OUTCOME_TRY(y, funcA(x)); + return funcC(y); + } +} // namespace issues210 + + +BOOST_OUTCOME_AUTO_TEST_CASE(issues_0210_test, "result<int, E> with error code compatible custom E does not TRY into a result<int, boost::system::error_code> function") +{ + BOOST_CHECK(issues210::func1(5).value() == 5); + BOOST_CHECK(issues210::func2(5).value() == 5); +} diff --git a/src/boost/libs/outcome/test/tests/issue0220.cpp b/src/boost/libs/outcome/test/tests/issue0220.cpp new file mode 100644 index 000000000..0da6eaf16 --- /dev/null +++ b/src/boost/libs/outcome/test/tests/issue0220.cpp @@ -0,0 +1,55 @@ +/* Unit testing for outcomes +(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (1 commit) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#include <boost/outcome/experimental/status_result.hpp> +#include <boost/outcome/try.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_NOT_POSIX +namespace issues220 +{ + namespace outcome_e = BOOST_OUTCOME_V2_NAMESPACE::experimental; + + template <class T, class E = outcome_e::error> using Result = outcome_e::status_result<T, E>; + + template <class T> using PosixResult = outcome_e::status_result<T, outcome_e::posix_code>; + + Result<int> convert(const PosixResult<int> &posix_result) { return Result<int>(posix_result); } +} // namespace issues220 +#endif + + +BOOST_OUTCOME_AUTO_TEST_CASE(issues_0220_test, "ubsan reports reference binding to null pointer") +{ +#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_NOT_POSIX + using namespace issues220; + BOOST_CHECK(convert(PosixResult<int>(0)).value() == 0); +#endif +} diff --git a/src/boost/libs/outcome/test/tests/noexcept-propagation.cpp b/src/boost/libs/outcome/test/tests/noexcept-propagation.cpp new file mode 100644 index 000000000..3754ff44d --- /dev/null +++ b/src/boost/libs/outcome/test/tests/noexcept-propagation.cpp @@ -0,0 +1,84 @@ +/* Unit testing for outcomes +(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (6 commits) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#include <boost/outcome/outcome.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +#ifdef _MSC_VER +#pragma warning(disable : 4127) // conditional expression is constant +#endif + +#ifndef BOOST_NO_EXCEPTIONS +// std nothrow traits seem to return random values if exceptions are disabled on MSVC +BOOST_OUTCOME_AUTO_TEST_CASE(works_outcome_noexcept, "Tests that the outcome correctly inherits noexcept from its type R") +{ + using namespace BOOST_OUTCOME_V2_NAMESPACE; + { + using type = outcome<int>; + BOOST_CHECK(std::is_nothrow_copy_constructible<type>::value); + BOOST_CHECK(std::is_nothrow_move_constructible<type>::value); + BOOST_CHECK(std::is_nothrow_copy_assignable<type>::value); + BOOST_CHECK(std::is_nothrow_move_assignable<type>::value); + BOOST_CHECK(std::is_nothrow_destructible<type>::value); + } + { + using type = outcome<std::string>; + BOOST_CHECK(std::is_nothrow_copy_constructible<type>::value == std::is_nothrow_copy_constructible<std::string>::value); + BOOST_CHECK(std::is_nothrow_move_constructible<type>::value == std::is_nothrow_move_constructible<std::string>::value); + BOOST_CHECK(std::is_nothrow_copy_assignable<type>::value == std::is_nothrow_copy_assignable<std::string>::value); + BOOST_CHECK(std::is_nothrow_move_assignable<type>::value == std::is_nothrow_move_assignable<std::string>::value); + BOOST_CHECK(std::is_nothrow_destructible<type>::value == std::is_nothrow_destructible<std::string>::value); + } + { + struct Except + { + int n; + Except() = delete; + Except(const Except & /*unused*/) noexcept(false) + : n(0) + { + } + Except(Except && /*unused*/) noexcept(false) + : n(0) + { + } + Except &operator=(const Except & /*unused*/) noexcept(false) { return *this; } + Except &operator=(Except && /*unused*/) noexcept(false) { return *this; } + ~Except() noexcept(false) { n = 0; } + }; + using type = outcome<Except>; + BOOST_CHECK(!std::is_nothrow_copy_constructible<type>::value); + BOOST_CHECK(!std::is_nothrow_move_constructible<type>::value); + BOOST_CHECK(!std::is_nothrow_copy_assignable<type>::value); + BOOST_CHECK(!std::is_nothrow_move_assignable<type>::value); + BOOST_CHECK(!std::is_nothrow_destructible<type>::value); + } +} +#endif diff --git a/src/boost/libs/outcome/test/tests/propagate.cpp b/src/boost/libs/outcome/test/tests/propagate.cpp new file mode 100644 index 000000000..0e3cbb545 --- /dev/null +++ b/src/boost/libs/outcome/test/tests/propagate.cpp @@ -0,0 +1,90 @@ +/* Unit testing for outcomes +(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (7 commits) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#include <boost/outcome/outcome.hpp> +#include <boost/outcome/try.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +BOOST_OUTCOME_AUTO_TEST_CASE(works_outcome_propagate, "Tests that the outcome propagates errors between different editions of itself") +{ + using namespace BOOST_OUTCOME_V2_NAMESPACE; + { + auto t0 = [&](int a) { return result<long>(boost::system::error_code(a, boost::system::generic_category())); }; + auto t1 = [&](int a) { + result<double> f(t0(a)); // double is constructible from long + BOOST_CHECK(!f.has_value()); + BOOST_CHECK(f.has_error()); + return f; + }; + auto t2 = [&](int a) { + result<void> f(t1(a).error()); + BOOST_CHECK(!f.has_value()); + BOOST_CHECK(f.has_error()); + return f; + }; + auto t3 = [&](int a) { + outcome<std::string> f(t2(a)); + BOOST_CHECK(!f.has_value()); + BOOST_CHECK(f.has_error()); + return f; + }; + BOOST_CHECK(t3(5).error().value() == 5); + result<int> a2{result<void>(in_place_type<void>)}; + result<int> a3{result<void>(boost::system::error_code(5, boost::system::generic_category()))}; + BOOST_CHECK(a2.has_value()); + BOOST_CHECK(!a2.has_error()); + BOOST_CHECK(!a3.has_value()); + BOOST_CHECK(a3.has_error()); + } + { + auto t0 = [&](int a) { return result<long>(a); }; + auto t1 = [&](int a) -> result<std::string> { + BOOST_OUTCOME_TRY(f, (t0(a))); + return std::to_string(f); + }; + BOOST_CHECK(t1(5).value() == "5"); + } + { + auto t0 = [&](int a) { return result<long>(a); }; + auto t1 = [&](int a) -> outcome<std::string> { + BOOST_OUTCOME_TRY(f, (t0(a))); + return std::to_string(f); + }; + BOOST_CHECK(t1(5).value() == "5"); + } + { + auto t0 = [&](int a) -> result<long> { return result<long>(a); }; + auto t1 = [&](int a) -> outcome<void> { + BOOST_OUTCOME_TRY((t0(a))); + return outcome<void>(in_place_type<void>); + }; + (void) t1(5); + } +} diff --git a/src/boost/libs/outcome/test/tests/serialisation.cpp b/src/boost/libs/outcome/test/tests/serialisation.cpp new file mode 100644 index 000000000..55d978dd5 --- /dev/null +++ b/src/boost/libs/outcome/test/tests/serialisation.cpp @@ -0,0 +1,49 @@ +/* Unit testing for outcomes +(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (7 commits) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#include <boost/outcome/iostream_support.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +BOOST_OUTCOME_AUTO_TEST_CASE(works_outcome_serialisation, "Tests that the outcome serialises and deserialises as intended") +{ +#if !defined(__APPLE__) || defined(__cpp_exceptions) + using namespace BOOST_OUTCOME_V2_NAMESPACE; + outcome<std::string> a("niall"), b(boost::system::error_code(5, boost::system::generic_category())), c(boost::copy_exception(std::ios_base::failure("A test failure message"))); + std::cout << "a contains " << print(a) << " and b contains " << print(b) << " and c contains " << print(c) << std::endl; + + std::stringstream ss; + outcome<int, std::string, long> d(success(5)); + ss << d; + ss.seekg(0); + outcome<int, std::string, long> e(failure("")); + ss >> e; + BOOST_CHECK(d == e); +#endif +} diff --git a/src/boost/libs/outcome/test/tests/success-failure.cpp b/src/boost/libs/outcome/test/tests/success-failure.cpp new file mode 100644 index 000000000..af1c3e46d --- /dev/null +++ b/src/boost/libs/outcome/test/tests/success-failure.cpp @@ -0,0 +1,69 @@ +/* Unit testing for outcomes +(C) 2017-2020 Niall Douglas <http://www.nedproductions.biz/> (10 commits) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#include <boost/outcome/result.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +#include <iostream> + +BOOST_OUTCOME_AUTO_TEST_CASE(works_success_failure, "Tests that the success and failure type sugars work as intended") +{ + using namespace BOOST_OUTCOME_V2_NAMESPACE; +#ifdef __cpp_deduction_guides + std::cout << "__cpp_deduction_guides = 1" << std::endl; +#endif + { + auto a = success(5); + auto b = success(); + auto c = success("hello"); + static_assert(std::is_same<decltype(a), success_type<int>>::value, ""); + static_assert(std::is_same<decltype(b), success_type<void>>::value, ""); + static_assert(std::is_same<decltype(c), success_type<const char *>>::value, ""); + static_assert(std::is_same<decltype(a)::value_type, int>::value, ""); + // static_assert(std::is_same<decltype(b.value), int>::value, ""); + static_assert(std::is_same<decltype(c)::value_type, const char *>::value, ""); + } +#if !defined(__APPLE__) || defined(__cpp_exceptions) + { + auto e = boost::copy_exception(std::exception()); + auto a = failure(5); + auto b = failure(5, e); + auto c = failure(5, 5); + static_assert(std::is_same<decltype(a), failure_type<int, void>>::value, ""); + static_assert(std::is_same<decltype(b), failure_type<int, boost::exception_ptr>>::value, ""); + static_assert(std::is_same<decltype(c), failure_type<int, int>>::value, ""); + static_assert(std::is_same<decltype(a)::error_type, int>::value, ""); + static_assert(std::is_same<decltype(b)::error_type, int>::value, ""); + static_assert(std::is_same<decltype(b)::exception_type, boost::exception_ptr>::value, ""); + static_assert(std::is_same<decltype(c)::error_type, int>::value, ""); + static_assert(std::is_same<decltype(c)::exception_type, int>::value, ""); + } +#endif +} diff --git a/src/boost/libs/outcome/test/tests/swap.cpp b/src/boost/libs/outcome/test/tests/swap.cpp new file mode 100644 index 000000000..0bcba3802 --- /dev/null +++ b/src/boost/libs/outcome/test/tests/swap.cpp @@ -0,0 +1,432 @@ +/* Unit testing for outcomes +(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (5 commits) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#include <boost/outcome/outcome.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +/* Should be this: + +78 move constructor count = 2 +65 move assignment count = 3 +78 move assignment count = 1 +65 move constructor count = 2 +78 move assignment count = 0 +65 move assignment count = 1 + +78 move constructor count = 1 +65 move assignment count = 2 +78 move assignment count = 0 +65 move assignment count = 1 +78 move assignment count = 0 + +78 move constructor count = 2 +65 move assignment count = 3 +78 move assignment count = 1 +65 move constructor count = 2 +78 move assignment count = 0 +65 move assignment count = 1 + +78 move constructor count = 1 +65 move assignment count = 2 +78 move assignment count = 0 +65 move assignment count = 1 +78 move assignment count = 0 + +78 move constructor count = 2 +65 move assignment count = 3 +78 move assignment count = 1 +65 move constructor count = 2 +78 move assignment count = 0 +65 move assignment count = 1 + +78 move constructor count = 1 +65 move assignment count = 2 +78 move assignment count = 0 +65 move assignment count = 1 +78 move assignment count = 0 + +78 move constructor count = 2 +65 move assignment count = 3 +78 move assignment count = 1 +65 move constructor count = 2 +78 move assignment count = 0 +65 move assignment count = 1 + +78 move constructor count = 1 +65 move assignment count = 2 +78 move assignment count = 0 +65 move assignment count = 1 +78 move assignment count = 0 +*/ + +#ifndef BOOST_NO_EXCEPTIONS +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4297) // function assumed not to throw an exception but does +#endif +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wterminate" +#endif +template <bool mc, bool ma> struct Throwy +{ + int count{0}, inc{0}, id{0}; + Throwy() = default; + Throwy(int c, int d, int i = 1) noexcept + : count(c) + , inc(i) + , id(d) + { + } + Throwy(const Throwy &) = delete; + Throwy &operator=(const Throwy &) = delete; + Throwy(Throwy &&o) noexcept(!mc) + : count(o.count - o.inc) + , inc(o.inc) + , id(o.id) // NOLINT + { + if(mc) + { + std::cout << " " << id << " move constructor count = " << count << std::endl; + if(!count) + { + std::cout << " " << id << " move constructor throws!" << std::endl; + throw std::bad_alloc(); + } + } + o.count = 0; + o.inc = 0; + o.id = 0; + } + Throwy &operator=(Throwy &&o) noexcept(!ma) + { + count = o.count - o.inc; + if(ma) + { + std::cout << " " << o.id << " move assignment count = " << count << std::endl; + if(!count) + { + std::cout << " " << o.id << " move assignment throws!" << std::endl; + throw std::bad_alloc(); + } + } + inc = o.inc; + id = o.id; + o.count = 0; + o.inc = 0; + o.id = 0; + return *this; + } + ~Throwy() = default; +}; +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif +#ifdef _MSC_VER +#pragma warning(pop) +#endif +enum class ErrorCode +{ + dummy +}; +enum class ErrorCode2 +{ + dummy +}; +template <bool mc, bool ma> using resulty1 = BOOST_OUTCOME_V2_NAMESPACE::result<Throwy<mc, ma>, ErrorCode, BOOST_OUTCOME_V2_NAMESPACE::policy::all_narrow>; +template <bool mc, bool ma> using resulty2 = BOOST_OUTCOME_V2_NAMESPACE::result<ErrorCode, Throwy<mc, ma>, BOOST_OUTCOME_V2_NAMESPACE::policy::all_narrow>; +template <bool mc, bool ma> using outcomey1 = BOOST_OUTCOME_V2_NAMESPACE::outcome<ErrorCode, Throwy<mc, ma>, ErrorCode2, BOOST_OUTCOME_V2_NAMESPACE::policy::all_narrow>; +template <bool mc, bool ma> using outcomey2 = BOOST_OUTCOME_V2_NAMESPACE::outcome<ErrorCode, ErrorCode2, Throwy<mc, ma>, BOOST_OUTCOME_V2_NAMESPACE::policy::all_narrow>; +#endif + +BOOST_OUTCOME_AUTO_TEST_CASE(works_outcome_swap, "Tests that the outcome swaps as intended") +{ + using namespace BOOST_OUTCOME_V2_NAMESPACE; + { // Does swap actually swap? + outcome<std::string> a("niall"), b("douglas"); + BOOST_CHECK(a.value() == "niall"); + BOOST_CHECK(b.value() == "douglas"); + swap(a, b); + BOOST_CHECK(a.value() == "douglas"); + BOOST_CHECK(b.value() == "niall"); + a = boost::system::errc::not_enough_memory; + swap(a, b); + BOOST_CHECK(a.value() == "niall"); + BOOST_CHECK(b.error() == boost::system::errc::not_enough_memory); + BOOST_CHECK(!a.has_lost_consistency()); + BOOST_CHECK(!b.has_lost_consistency()); + } +#ifndef BOOST_NO_EXCEPTIONS + { // Is noexcept propagated? + using nothrow_t = Throwy<false, false>; + using nothrow = resulty1<false, false>; + static_assert(std::is_nothrow_move_constructible<nothrow_t>::value, "throwy not correct!"); + static_assert(std::is_nothrow_move_assignable<nothrow_t>::value, "throwy not correct!"); + static_assert(std::is_nothrow_move_constructible<nothrow>::value, "type not correct!"); + static_assert(std::is_nothrow_move_assignable<nothrow>::value, "type not correct!"); + + static_assert(detail::is_nothrow_swappable<nothrow_t>::value, "is_nothrow_swappable is not correct!"); + + static_assert(noexcept(nothrow(0, 0)), "type has a throwing value constructor!"); + nothrow a(1, 78), b(1, 65); + a.swap(b); + static_assert(noexcept(a.swap(b)), "type has a throwing swap!"); + } + { // Is noexcept propagated? + using nothrow_t = Throwy<false, false>; + using nothrow = resulty2<false, false>; + static_assert(std::is_nothrow_move_constructible<nothrow_t>::value, "throwy not correct!"); + static_assert(std::is_nothrow_move_assignable<nothrow_t>::value, "throwy not correct!"); + static_assert(std::is_nothrow_move_constructible<nothrow>::value, "type not correct!"); + static_assert(std::is_nothrow_move_assignable<nothrow>::value, "type not correct!"); + + static_assert(detail::is_nothrow_swappable<nothrow_t>::value, "is_nothrow_swappable is not correct!"); + + static_assert(noexcept(nothrow(0, 0)), "type has a throwing value constructor!"); + nothrow a(1, 78), b(1, 65); + a.swap(b); + static_assert(noexcept(a.swap(b)), "type has a throwing swap!"); + } + + { // Does swap implement the strong guarantee? + using throwy_t = Throwy<true, true>; + using throwy = resulty1<true, true>; + static_assert(!std::is_nothrow_move_constructible<throwy_t>::value, "throwy not correct!"); + static_assert(!std::is_nothrow_move_assignable<throwy_t>::value, "throwy not correct!"); + static_assert(!std::is_nothrow_move_constructible<throwy>::value, "type not correct!"); + static_assert(!std::is_nothrow_move_assignable<throwy>::value, "type not correct!"); + + static_assert(!detail::is_nothrow_swappable<throwy_t>::value, "is_nothrow_swappable is not correct!"); + + std::cout << "Result value first swap succeeds, second swap second move assignment throws:" << std::endl; + { + throwy a(3, 78), b(4, 65); + a.swap(b); + static_assert(!noexcept(a.swap(b)), "type has a non-throwing swap!"); + BOOST_CHECK(a.value().id == 65); + BOOST_CHECK(b.value().id == 78); + try + { + a.swap(b); // fails on first assignment + BOOST_REQUIRE(false); + } + catch(const std::bad_alloc & /*unused*/) + { + BOOST_CHECK(a.value().id == 65); // ensure it is perfectly restored + BOOST_CHECK(b.value().id == 78); + } + BOOST_CHECK(!a.has_lost_consistency()); + BOOST_CHECK(!b.has_lost_consistency()); + } + std::cout << "\nResult value second move assignment throws, on recover second move assignment throws:" << std::endl; + { + throwy a(2, 78), b(3, 65); // fails on second assignment, cannot restore + try + { + a.swap(b); + BOOST_REQUIRE(false); + } + catch(const std::bad_alloc & /*unused*/) + { + BOOST_CHECK(a.has_lost_consistency()); // both must be marked tainted + BOOST_CHECK(b.has_lost_consistency()); + } + } + } + std::cout << "\nResult error first swap succeeds, second swap first move assignment throws:" << std::endl; + { // Does swap implement the strong guarantee? + using throwy_t = Throwy<true, true>; + using throwy = resulty2<true, true>; + static_assert(!std::is_nothrow_move_constructible<throwy_t>::value, "throwy not correct!"); + static_assert(!std::is_nothrow_move_assignable<throwy_t>::value, "throwy not correct!"); + static_assert(!std::is_nothrow_move_constructible<throwy>::value, "type not correct!"); + static_assert(!std::is_nothrow_move_assignable<throwy>::value, "type not correct!"); + + static_assert(!detail::is_nothrow_swappable<throwy_t>::value, "is_nothrow_swappable is not correct!"); + + { + throwy a(3, 78), b(4, 65); + a.swap(b); + static_assert(!noexcept(a.swap(b)), "type has a non-throwing swap!"); + BOOST_CHECK(a.error().id == 65); + BOOST_CHECK(b.error().id == 78); + try + { + a.swap(b); // fails on first assignment + BOOST_REQUIRE(false); + } + catch(const std::bad_alloc & /*unused*/) + { + BOOST_CHECK(a.error().id == 65); // ensure it is perfectly restored + BOOST_CHECK(b.error().id == 78); + } + BOOST_CHECK(!a.has_lost_consistency()); + BOOST_CHECK(!b.has_lost_consistency()); + } + std::cout << "\nResult error second move assignment throws, on recover second move assignment throws:" << std::endl; + { + throwy a(2, 78), b(3, 65); // fails on second assignment, cannot restore + try + { + a.swap(b); + BOOST_REQUIRE(false); + } + catch(const std::bad_alloc & /*unused*/) + { + BOOST_CHECK(a.has_lost_consistency()); // both must be marked tainted + BOOST_CHECK(b.has_lost_consistency()); + } + } + } + + { // Is noexcept propagated? + using nothrow_t = Throwy<false, false>; + using nothrow = outcomey1<false, false>; + static_assert(std::is_nothrow_move_constructible<nothrow_t>::value, "throwy not correct!"); + static_assert(std::is_nothrow_move_assignable<nothrow_t>::value, "throwy not correct!"); + static_assert(std::is_nothrow_move_constructible<nothrow>::value, "type not correct!"); + static_assert(std::is_nothrow_move_assignable<nothrow>::value, "type not correct!"); + + static_assert(detail::is_nothrow_swappable<nothrow_t>::value, "is_nothrow_swappable is not correct!"); + + static_assert(noexcept(nothrow(0, 0)), "type has a throwing value constructor!"); + nothrow a(1, 78), b(1, 65); + a.swap(b); + static_assert(noexcept(a.swap(b)), "type has a throwing swap!"); + } + { // Is noexcept propagated? + using nothrow_t = Throwy<false, false>; + using nothrow = outcomey1<false, false>; + static_assert(std::is_nothrow_move_constructible<nothrow_t>::value, "throwy not correct!"); + static_assert(std::is_nothrow_move_assignable<nothrow_t>::value, "throwy not correct!"); + static_assert(std::is_nothrow_move_constructible<nothrow>::value, "type not correct!"); + static_assert(std::is_nothrow_move_assignable<nothrow>::value, "type not correct!"); + + static_assert(detail::is_nothrow_swappable<nothrow_t>::value, "is_nothrow_swappable is not correct!"); + + static_assert(noexcept(nothrow(0, 0)), "type has a throwing value constructor!"); + nothrow a(1, 78), b(1, 65); + a.swap(b); + static_assert(noexcept(a.swap(b)), "type has a throwing swap!"); + } + + std::cout << "\n\nOutcome value first swap succeeds, second swap first move assignment throws:" << std::endl; + { // Does swap implement the strong guarantee? + using throwy_t = Throwy<true, true>; + using throwy = outcomey1<true, true>; + static_assert(!std::is_nothrow_move_constructible<throwy_t>::value, "throwy not correct!"); + static_assert(!std::is_nothrow_move_assignable<throwy_t>::value, "throwy not correct!"); + static_assert(!std::is_nothrow_move_constructible<throwy>::value, "type not correct!"); + static_assert(!std::is_nothrow_move_assignable<throwy>::value, "type not correct!"); + + static_assert(!detail::is_nothrow_swappable<throwy_t>::value, "is_nothrow_swappable is not correct!"); + + { + throwy a(3, 78), b(4, 65); + a.swap(b); + static_assert(!noexcept(a.swap(b)), "type has a non-throwing swap!"); + BOOST_CHECK(a.error().id == 65); + BOOST_CHECK(b.error().id == 78); + try + { + a.swap(b); // fails on first assignment + BOOST_REQUIRE(false); + } + catch(const std::bad_alloc & /*unused*/) + { + BOOST_CHECK(a.error().id == 65); // ensure it is perfectly restored + BOOST_CHECK(b.error().id == 78); + } + BOOST_CHECK(!a.has_lost_consistency()); + BOOST_CHECK(!b.has_lost_consistency()); + } + std::cout << "\nOutcome value second move assignment throws, on recover second move assignment throws:" << std::endl; + { + throwy a(2, 78), b(3, 65); // fails on second assignment, cannot restore + try + { + a.swap(b); + BOOST_REQUIRE(false); + } + catch(const std::bad_alloc & /*unused*/) + { + BOOST_CHECK(a.has_lost_consistency()); // both must be marked tainted + BOOST_CHECK(b.has_lost_consistency()); + } + } + } + std::cout << "\nOutcome error first swap succeeds, second swap first move assignment throws:" << std::endl; + { // Does swap implement the strong guarantee? + using throwy_t = Throwy<true, true>; + using throwy = outcomey2<true, true>; + static_assert(!std::is_nothrow_move_constructible<throwy_t>::value, "throwy not correct!"); + static_assert(!std::is_nothrow_move_assignable<throwy_t>::value, "throwy not correct!"); + static_assert(!std::is_nothrow_move_constructible<throwy>::value, "type not correct!"); + static_assert(!std::is_nothrow_move_assignable<throwy>::value, "type not correct!"); + + static_assert(!detail::is_nothrow_swappable<throwy_t>::value, "is_nothrow_swappable is not correct!"); + + { + throwy a(3, 78), b(4, 65); + a.swap(b); + static_assert(!noexcept(a.swap(b)), "type has a non-throwing swap!"); + BOOST_CHECK(a.exception().id == 65); + BOOST_CHECK(b.exception().id == 78); + try + { + a.swap(b); // fails on first assignment + BOOST_REQUIRE(false); + } + catch(const std::bad_alloc & /*unused*/) + { + BOOST_CHECK(a.exception().id == 65); // ensure it is perfectly restored + BOOST_CHECK(b.exception().id == 78); + } + BOOST_CHECK(!a.has_lost_consistency()); + BOOST_CHECK(!b.has_lost_consistency()); + } + std::cout << "\nOutcome error second move assignment throws, on recover second move assignment throws:" << std::endl; + { + throwy a(2, 78), b(3, 65); // fails on second assignment, cannot restore + try + { + a.swap(b); + BOOST_REQUIRE(false); + } + catch(const std::bad_alloc & /*unused*/) + { + BOOST_CHECK(a.has_lost_consistency()); // both must be marked tainted + BOOST_CHECK(b.has_lost_consistency()); + } + } + std::cout << std::endl; + } +#endif +} diff --git a/src/boost/libs/outcome/test/tests/udts.cpp b/src/boost/libs/outcome/test/tests/udts.cpp new file mode 100644 index 000000000..740ca51d2 --- /dev/null +++ b/src/boost/libs/outcome/test/tests/udts.cpp @@ -0,0 +1,154 @@ +/* Unit testing for outcomes +(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (7 commits) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#ifdef _MSC_VER +#pragma warning(disable : 4702) // unreachable code +#endif + +#include <boost/outcome/outcome.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +BOOST_OUTCOME_AUTO_TEST_CASE(works_outcome_udts, "Tests that the outcome works as intended with user-defined types") +{ + using namespace BOOST_OUTCOME_V2_NAMESPACE; + // No default constructor, no copy/move, no assignment + { + struct udt + { + int a; + explicit udt(int _a) + : a(_a) + { + } + udt() = delete; + udt(const udt &) = delete; + udt(udt &&) = delete; + udt &operator=(const udt &) = delete; + udt &operator=(udt &&) = delete; + ~udt() = default; + }; + outcome<udt> foo(in_place_type<udt>, 5); + BOOST_CHECK(5 == foo.value().a); + } +#ifndef BOOST_NO_EXCEPTIONS + // Emplace construct, throws during move and copy + { + struct udt + { + std::string a; + explicit udt(std::string _a) + : a(std::move(_a)) + { + } + udt() = delete; + udt(const udt & /*unused*/) { throw std::logic_error("copy"); } + udt(udt && /*unused*/) noexcept(false) { throw std::logic_error("move"); } // NOLINT + udt &operator=(const udt & /*unused*/) { throw std::logic_error("copy"); } + udt &operator=(udt && /*unused*/) noexcept(false) { throw std::logic_error("move"); } // NOLINT + ~udt() { a.clear(); } + }; + static_assert(!std::is_default_constructible<udt>::value, "udt is default constructible"); + static_assert(std::is_copy_constructible<udt>::value, "udt is not copy constructible"); + static_assert(std::is_move_constructible<udt>::value, "udt is not move constructible"); + static_assert(!std::is_default_constructible<outcome<udt>>::value, "outcome<udt> is default constructible"); + static_assert(std::is_copy_constructible<outcome<udt>>::value, "outcome<udt> is not copy constructible"); + static_assert(std::is_move_constructible<outcome<udt>>::value, "outcome<udt> is not move constructible"); + // Emplace constructs + outcome<udt> foo(in_place_type<udt>, "niall"); + BOOST_CHECK("niall" == foo.value().a); + try + { + auto foo2(foo); // NOLINT + BOOST_CHECK(false); + } + catch(const std::logic_error &e) + { + BOOST_CHECK(!strcmp(e.what(), "copy")); + } + catch(...) + { + BOOST_CHECK(false); + } + BOOST_CHECK("niall" == foo.value().a); + try + { + auto foo2(std::move(foo)); + BOOST_CHECK(false); + } + catch(const std::logic_error &e) + { + BOOST_CHECK(!strcmp(e.what(), "move")); + } + catch(...) + { + BOOST_CHECK(false); + } + BOOST_CHECK("niall" == foo.value().a); // NOLINT + // Does throwing during copy assignment work? + { + outcome<udt> foo2(in_place_type<udt>, "douglas"); + try + { + foo2 = foo; + BOOST_CHECK(false); + } + catch(const std::logic_error &e) + { + BOOST_CHECK(!strcmp(e.what(), "copy")); + BOOST_CHECK(foo2.value().a == "douglas"); + } + catch(...) + { + BOOST_CHECK(false); + } + BOOST_CHECK("niall" == foo.value().a); + } + // Does throwing during move assignment work? + { + outcome<udt> foo2(in_place_type<udt>, "douglas"); + try + { + foo2 = std::move(foo); + BOOST_CHECK(false); + } + catch(const std::logic_error &e) + { + BOOST_CHECK(!strcmp(e.what(), "move")); + BOOST_CHECK(foo2.value().a == "douglas"); + } + catch(...) + { + BOOST_CHECK(false); + } + BOOST_CHECK("niall" == foo.value().a); // NOLINT + } + } +#endif +} diff --git a/src/boost/libs/outcome/test/tests/value-or-error.cpp b/src/boost/libs/outcome/test/tests/value-or-error.cpp new file mode 100644 index 000000000..558e229a7 --- /dev/null +++ b/src/boost/libs/outcome/test/tests/value-or-error.cpp @@ -0,0 +1,54 @@ +/* Unit testing for outcomes +(C) 2013-2020 Niall Douglas <http://www.nedproductions.biz/> (3 commits) + + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#include <boost/outcome/outcome.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/test/unit_test_monitor.hpp> + +BOOST_OUTCOME_AUTO_TEST_CASE(works_outcome_valueorerror, "Tests that outcome constructs from ValueOrError and ValueOrNone concept inputs") +{ + using namespace BOOST_OUTCOME_V2_NAMESPACE; + { + struct value_or_error + { + using value_type = int; + using error_type = void; + bool has_value() const { return true; } + int value() const { return 78; } + void error() const {} + } a; + static_assert(convert::ValueOrNone<value_or_error>, ""); + static_assert(convert::ValueOrError<value_or_error>, ""); + BOOST_CHECK((convert::value_or_error<result<long>, value_or_error>{}(a).value() == 78)); + + result<long> b(a); + BOOST_CHECK(b.has_value()); + BOOST_CHECK(b.value() == 78); + } +} |