diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 92eba5a..5e734d2 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -54,6 +54,8 @@ set(SOURCES src/make_rejected.cpp src/make_resolved.cpp src/race.cpp + src/settled.cpp + src/smoke.cpp src/then.cpp ) diff --git a/tests/src/settled.cpp b/tests/src/settled.cpp new file mode 100644 index 0000000..bc05b95 --- /dev/null +++ b/tests/src/settled.cpp @@ -0,0 +1,284 @@ +/****************************************************************************** +** +** Copyright (C) 2023 Ivan Pinezhaninov +** +** This file is part of the async_promise project - which can be found at +** https://github.com/IvanPinezhaninov/async_promise/. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ALL KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ALL CLAIM, +** DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +** OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR +** THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +******************************************************************************/ + +// async_promise +#include + +// catch2 +#include +#include + +// local +#include "common.h" + + +TEST_CASE("Resolved settled object copy constructor", "[settled]") +{ + async::settled obj1{str1}; + REQUIRE(obj1.type == async::settle_type::resolved); + REQUIRE(obj1.result == str1); + + auto obj2 = obj1; + REQUIRE(obj2.type == async::settle_type::resolved); + REQUIRE(obj2.result == str1); + REQUIRE(obj2.type == obj1.type); + REQUIRE(obj2.result == obj1.result); +} + + +TEST_CASE("Resolved settled object move constructor", "[settled]") +{ + async::settled obj1{str1}; + REQUIRE(obj1.type == async::settle_type::resolved); + REQUIRE(obj1.result == str1); + + auto obj2 = std::move(obj1); + REQUIRE(obj2.type == async::settle_type::resolved); + REQUIRE(obj2.result == str1); +} + + +TEST_CASE("Resolved settled object copy operator", "[settled]") +{ + async::settled obj1{str1}; + REQUIRE(obj1.type == async::settle_type::resolved); + REQUIRE(obj1.result == str1); + + async::settled obj2{str2}; + REQUIRE(obj2.type == async::settle_type::resolved); + REQUIRE(obj2.result == str2); + + obj2 = obj1; + REQUIRE(obj2.type == async::settle_type::resolved); + REQUIRE(obj2.result == str1); + REQUIRE(obj2.type == obj1.type); + REQUIRE(obj2.result == obj1.result); +} + + +TEST_CASE("Resolved settled object move operator", "[settled]") +{ + async::settled obj1{str1}; + REQUIRE(obj1.type == async::settle_type::resolved); + REQUIRE(obj1.result == str1); + + async::settled obj2{str2}; + REQUIRE(obj2.type == async::settle_type::resolved); + REQUIRE(obj2.result == str2); + + obj2 = std::move(obj1); + REQUIRE(obj2.type == async::settle_type::resolved); + REQUIRE(obj2.result == str1); +} + + +TEST_CASE("Rejected settled object copy constructor", "[settled]") +{ + async::settled obj1{std::make_exception_ptr(std::runtime_error{str1})}; + REQUIRE(obj1.type == async::settle_type::rejected); + REQUIRE_THROWS_MATCHES(std::rethrow_exception(obj1.error), std::runtime_error, Catch::Matchers::Message(str1)); + + auto obj2 = obj1; + REQUIRE(obj2.type == async::settle_type::rejected); + REQUIRE_THROWS_MATCHES(std::rethrow_exception(obj2.error), std::runtime_error, Catch::Matchers::Message(str1)); +} + + +TEST_CASE("Rejected settled object move constructor", "[settled]") +{ + async::settled obj1{std::make_exception_ptr(std::runtime_error{str1})}; + REQUIRE(obj1.type == async::settle_type::rejected); + REQUIRE_THROWS_MATCHES(std::rethrow_exception(obj1.error), std::runtime_error, Catch::Matchers::Message(str1)); + + auto obj2 = std::move(obj1); + REQUIRE(obj2.type == async::settle_type::rejected); + REQUIRE_THROWS_MATCHES(std::rethrow_exception(obj2.error), std::runtime_error, Catch::Matchers::Message(str1)); +} + + +TEST_CASE("Rejected settled object copy operator", "[settled]") +{ + async::settled obj1{std::make_exception_ptr(std::runtime_error{str1})}; + REQUIRE(obj1.type == async::settle_type::rejected); + REQUIRE_THROWS_MATCHES(std::rethrow_exception(obj1.error), std::runtime_error, Catch::Matchers::Message(str1)); + + async::settled obj2{std::make_exception_ptr(std::runtime_error{str2})}; + REQUIRE(obj2.type == async::settle_type::rejected); + REQUIRE_THROWS_MATCHES(std::rethrow_exception(obj2.error), std::runtime_error, Catch::Matchers::Message(str2)); + + obj2 = obj1; + REQUIRE(obj2.type == obj1.type); + REQUIRE(obj2.error == obj1.error); +} + + +TEST_CASE("Rejected settled object move operator", "[settled]") +{ + async::settled obj1{std::make_exception_ptr(std::runtime_error{str1})}; + REQUIRE(obj1.type == async::settle_type::rejected); + REQUIRE_THROWS_MATCHES(std::rethrow_exception(obj1.error), std::runtime_error, Catch::Matchers::Message(str1)); + + async::settled obj2{std::make_exception_ptr(std::runtime_error{str2})}; + REQUIRE(obj2.type == async::settle_type::rejected); + REQUIRE_THROWS_MATCHES(std::rethrow_exception(obj2.error), std::runtime_error, Catch::Matchers::Message(str2)); + + obj2 = std::move(obj1); + REQUIRE(obj2.type == async::settle_type::rejected); + REQUIRE_THROWS_MATCHES(std::rethrow_exception(obj2.error), std::runtime_error, Catch::Matchers::Message(str1)); +} + + +TEST_CASE("Settled object swap method", "[settled]") +{ + async::settled obj1{str1}; + REQUIRE(obj1.type == async::settle_type::resolved); + REQUIRE(obj1.result == str1); + + async::settled obj2{std::make_exception_ptr(std::runtime_error{str2})}; + REQUIRE(obj2.type == async::settle_type::rejected); + REQUIRE_THROWS_MATCHES(std::rethrow_exception(obj2.error), std::runtime_error, Catch::Matchers::Message(str2)); + + obj1.swap(obj2); + + REQUIRE(obj1.type == async::settle_type::rejected); + REQUIRE_THROWS_MATCHES(std::rethrow_exception(obj1.error), std::runtime_error, Catch::Matchers::Message(str2)); + + REQUIRE(obj2.type == async::settle_type::resolved); + REQUIRE(obj2.result == str1); +} + + +TEST_CASE("Resolved settled void object copy constructor", "[settled]") +{ + async::settled obj1; + REQUIRE(obj1.type == async::settle_type::resolved); + + auto obj2 = obj1; + REQUIRE(obj2.type == async::settle_type::resolved); + REQUIRE(obj2.type == obj1.type); +} + + +TEST_CASE("Resolved settled void object move constructor", "[settled]") +{ + async::settled obj1; + REQUIRE(obj1.type == async::settle_type::resolved); + + auto obj2 = std::move(obj1); + REQUIRE(obj2.type == async::settle_type::resolved); +} + + +TEST_CASE("Resolved settled void object copy operator", "[settled]") +{ + async::settled obj1; + REQUIRE(obj1.type == async::settle_type::resolved); + + async::settled obj2; + REQUIRE(obj2.type == async::settle_type::resolved); + + obj2 = obj1; + REQUIRE(obj2.type == async::settle_type::resolved); + REQUIRE(obj2.type == obj1.type); +} + + +TEST_CASE("Resolved settled void object move operator", "[settled]") +{ + async::settled obj1; + REQUIRE(obj1.type == async::settle_type::resolved); + + async::settled obj2; + REQUIRE(obj2.type == async::settle_type::resolved); + + obj2 = std::move(obj1); + REQUIRE(obj2.type == async::settle_type::resolved); +} + + +TEST_CASE("Rejected settled void object copy constructor", "[settled]") +{ + async::settled obj1{std::make_exception_ptr(std::runtime_error{str1})}; + REQUIRE(obj1.type == async::settle_type::rejected); + REQUIRE_THROWS_MATCHES(std::rethrow_exception(obj1.error), std::runtime_error, Catch::Matchers::Message(str1)); + + auto obj2 = obj1; + REQUIRE(obj2.type == async::settle_type::rejected); + REQUIRE_THROWS_MATCHES(std::rethrow_exception(obj2.error), std::runtime_error, Catch::Matchers::Message(str1)); +} + + +TEST_CASE("Rejected settled void object move constructor", "[settled]") +{ + async::settled obj1{std::make_exception_ptr(std::runtime_error{str1})}; + REQUIRE(obj1.type == async::settle_type::rejected); + REQUIRE_THROWS_MATCHES(std::rethrow_exception(obj1.error), std::runtime_error, Catch::Matchers::Message(str1)); + + auto obj2 = std::move(obj1); + REQUIRE(obj2.type == async::settle_type::rejected); + REQUIRE_THROWS_MATCHES(std::rethrow_exception(obj2.error), std::runtime_error, Catch::Matchers::Message(str1)); +} + + +TEST_CASE("Rejected settled void object copy operator", "[settled]") +{ + async::settled obj1{std::make_exception_ptr(std::runtime_error{str1})}; + REQUIRE(obj1.type == async::settle_type::rejected); + REQUIRE_THROWS_MATCHES(std::rethrow_exception(obj1.error), std::runtime_error, Catch::Matchers::Message(str1)); + + async::settled obj2{std::make_exception_ptr(std::runtime_error{str2})}; + REQUIRE(obj2.type == async::settle_type::rejected); + REQUIRE_THROWS_MATCHES(std::rethrow_exception(obj2.error), std::runtime_error, Catch::Matchers::Message(str2)); + + obj2 = obj1; + REQUIRE(obj2.type == obj1.type); + REQUIRE(obj2.error == obj1.error); +} + + +TEST_CASE("Rejected settled void object move operator", "[settled]") +{ + async::settled obj1{std::make_exception_ptr(std::runtime_error{str1})}; + REQUIRE(obj1.type == async::settle_type::rejected); + REQUIRE_THROWS_MATCHES(std::rethrow_exception(obj1.error), std::runtime_error, Catch::Matchers::Message(str1)); + + async::settled obj2{std::make_exception_ptr(std::runtime_error{str2})}; + REQUIRE(obj2.type == async::settle_type::rejected); + REQUIRE_THROWS_MATCHES(std::rethrow_exception(obj2.error), std::runtime_error, Catch::Matchers::Message(str2)); + + obj2 = std::move(obj1); + REQUIRE(obj2.type == async::settle_type::rejected); + REQUIRE_THROWS_MATCHES(std::rethrow_exception(obj2.error), std::runtime_error, Catch::Matchers::Message(str1)); +} + + +TEST_CASE("Settled object void swap method", "[settled]") +{ + async::settled obj1; + REQUIRE(obj1.type == async::settle_type::resolved); + + async::settled obj2{std::make_exception_ptr(std::runtime_error{str2})}; + REQUIRE(obj2.type == async::settle_type::rejected); + REQUIRE_THROWS_MATCHES(std::rethrow_exception(obj2.error), std::runtime_error, Catch::Matchers::Message(str2)); + + obj1.swap(obj2); + + REQUIRE(obj1.type == async::settle_type::rejected); + REQUIRE_THROWS_MATCHES(std::rethrow_exception(obj1.error), std::runtime_error, Catch::Matchers::Message(str2)); + + REQUIRE(obj2.type == async::settle_type::resolved); +} diff --git a/tests/src/smoke.cpp b/tests/src/smoke.cpp new file mode 100644 index 0000000..11caecc --- /dev/null +++ b/tests/src/smoke.cpp @@ -0,0 +1,442 @@ +/****************************************************************************** +** +** Copyright (C) 2023 Ivan Pinezhaninov +** +** This file is part of the async_promise project - which can be found at +** https://github.com/IvanPinezhaninov/async_promise/. +** +** 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 AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +** DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +** OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR +** THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +******************************************************************************/ + +// stl +#include + +// async_promise +#include + +// catch2 +#include +#include + + +template class Container, typename Allocator> +static T sum(const Container& c) +{ + return std::accumulate(c.cbegin(), c.cend(), T{}); +} + + +template class Container, typename Allocator> +static T sum_settled(const Container, Allocator>& c) +{ + using namespace std::placeholders; + return std::accumulate(c.cbegin(), c.cend(), T{}, + std::bind(std::plus(), _1, std::bind(&async::settled::result, _2))); +} + + +TEST_CASE("Smoke make then", "[smoke]") +{ + auto future = async::make_promise([] (int val) { return val + 2; }, 1) + .then([] (int val) { return val + 3; }) + .then([] (int val) { return val + 4; }) + .then([] (int val) { return val + 5; }) + .run(); + + auto res = 0; + REQUIRE_NOTHROW(res = future.get()); + static constexpr auto exp = 1 + 2 + 3 + 4 + 5; + REQUIRE(res == exp); +} + + +TEST_CASE("Smoke make then no arg", "[smoke]") +{ + auto future = async::make_promise([] () { return 1; }) + .then([] (int val) { return val + 2; }) + .then([] (int val) { return val + 3; }) + .then([] (int val) { return val + 4; }) + .run(); + + auto res = 0; + REQUIRE_NOTHROW(res = future.get()); + static constexpr auto exp = 1 + 2 + 3 + 4; + REQUIRE(res == exp); +} + + +TEST_CASE("Smoke then", "[smoke]") +{ + auto future = async::make_resolved_promise(1) + .then([] (int val) { return val + 2; }) + .then([] (int val) { return val + 3; }) + .then([] (int val) { return val + 4; }) + .run(); + + auto res = 0; + REQUIRE_NOTHROW(res = future.get()); + static constexpr auto exp = 1 + 2 + 3 + 4; + REQUIRE(res == exp); +} + + +TEST_CASE("Smoke then no arg", "[smoke]") +{ + auto future = async::make_resolved_promise(1) + .then([] (int val) { return val + 2; }) + .then([] () { return 3; }) + .then([] (int val) { return val + 4; }) + .run(); + + auto res = 0; + REQUIRE_NOTHROW(res = future.get()); + static constexpr auto exp = 3 + 4; + REQUIRE(res == exp); +} + + +TEST_CASE("Smoke all", "[smoke]") +{ + std::vector funcs + { + [] (int val) { return val + 3; }, + [] (int val) { return val + 4; }, + [] (int val) { return val + 5; }, + }; + + auto future = async::make_resolved_promise(1) + .then([] (int val) { return val + 2; }) + .all(funcs) + .then([] (const std::vector& v) { return sum(v); }) + .run(); + + auto res = 0; + REQUIRE_NOTHROW(res = future.get()); + static constexpr auto exp = (1 + 2 + 3) + (1 + 2 + 4) + (1 + 2 + 5); + REQUIRE(res == exp); +} + + +TEST_CASE("Smoke all no arg", "[smoke]") +{ + std::vector funcs + { + [] () { return 3; }, + [] () { return 4; }, + [] () { return 5; }, + }; + + auto future = async::make_resolved_promise(1) + .then([] (int val) { return val + 2; }) + .all(funcs) + .then([] (const std::vector& v) { return sum(v); }) + .run(); + + auto res = 0; + REQUIRE_NOTHROW(res = future.get()); + static constexpr auto exp = 3 + 4 + 5; + REQUIRE(res == exp); +} + + +TEST_CASE("Smoke all settled", "[smoke]") +{ + std::vector funcs + { + [] (int val) { return val + 3; }, + [] (int val) { return val + 4; }, + [] (int val) { return val + 5; }, + }; + + auto future = async::make_resolved_promise(1) + .then([] (int val) { return val + 2; }) + .all_settled(funcs) + .then([] (const std::vector>& v) { return sum_settled(v); }) + .run(); + + auto res = 0; + REQUIRE_NOTHROW(res = future.get()); + static constexpr auto exp = (1 + 2 + 3) + (1 + 2 + 4) + (1 + 2 + 5); + REQUIRE(res == exp); +} + + +TEST_CASE("Smoke all settled no arg", "[smoke]") +{ + std::vector funcs + { + [] () { return 3; }, + [] () { return 4; }, + [] () { return 5; }, + }; + + auto future = async::make_resolved_promise(1) + .then([] (int val) { return val + 2; }) + .all_settled(funcs) + .then([] (const std::vector>& v) { return sum_settled(v); }) + .run(); + + auto res = 0; + REQUIRE_NOTHROW(res = future.get()); + static constexpr auto exp = 3 + 4 + 5; + REQUIRE(res == exp); +} + + +TEST_CASE("Smoke any", "[smoke]") +{ + std::vector funcs + { + [] (int val) { return val + 3; }, + [] (int val) { return val + 3; }, + [] (int val) { return val + 3; }, + }; + + auto future = async::make_resolved_promise(1) + .then([] (int val) { return val + 2; }) + .any(funcs) + .then([] (int val) { return val + 4; }) + .run(); + + auto res = 0; + REQUIRE_NOTHROW(res = future.get()); + static constexpr auto exp = 1 + 2 + 3 + 4; + REQUIRE(res == exp); +} + + +TEST_CASE("Smoke any no arg", "[smoke]") +{ + std::vector funcs + { + [] () { return 3; }, + [] () { return 3; }, + [] () { return 3; }, + }; + + auto future = async::make_resolved_promise(1) + .then([] (int val) { return val + 2; }) + .any(funcs) + .then([] (int val) { return val + 4; }) + .run(); + + auto res = 0; + REQUIRE_NOTHROW(res = future.get()); + static constexpr auto exp = 3 + 4; + REQUIRE(res == exp); +} + + +TEST_CASE("Smoke race", "[smoke]") +{ + std::vector funcs + { + [] (int val) { return val + 3; }, + [] (int val) { return val + 3; }, + [] (int val) { return val + 3; }, + }; + + auto future = async::make_resolved_promise(1) + .then([] (int val) { return val + 2; }) + .race(funcs) + .then([] (int val) { return val + 4; }) + .run(); + + auto res = 0; + REQUIRE_NOTHROW(res = future.get()); + static constexpr auto exp = 1 + 2 + 3 + 4; + REQUIRE(res == exp); +} + + +TEST_CASE("Smoke race no arg", "[smoke]") +{ + std::vector funcs + { + [] () { return 3; }, + [] () { return 3; }, + [] () { return 3; }, + }; + + auto future = async::make_resolved_promise(1) + .then([] (int val) { return val + 2; }) + .race(funcs) + .then([] (int val) { return val + 4; }) + .run(); + + auto res = 0; + REQUIRE_NOTHROW(res = future.get()); + static constexpr auto exp = 3 + 4; + REQUIRE(res == exp); +} + + +TEST_CASE("Smoke static all", "[smoke]") +{ + std::vector funcs + { + [] (int val1, int val2, int val3) { return val1 + val2 + val3 + 4; }, + [] (int val1, int val2, int val3) { return val1 + val2 + val3 + 5; }, + [] (int val1, int val2, int val3) { return val1 + val2 + val3 + 6; }, + }; + + auto future = async::make_promise_all(funcs, 1, 2, 3) + .then([] (const std::vector& v) { return sum(v); }) + .then([] (int val) { return val + 7; }) + .run(); + + auto res = 0; + REQUIRE_NOTHROW(res = future.get()); + static constexpr auto exp = (1 + 2 + 3 + 4) + (1 + 2 + 3 + 5) + (1 + 2 + 3 + 6) + 7; + REQUIRE(res == exp); +} + + +TEST_CASE("Smoke static all no args", "[smoke]") +{ + std::vector funcs + { + [] () { return 1; }, + [] () { return 2; }, + [] () { return 3; }, + }; + + auto future = async::make_promise_all(funcs) + .then([] (const std::vector& v) { return sum(v); }) + .then([] (int val) { return val + 4; }) + .run(); + + auto res = 0; + REQUIRE_NOTHROW(res = future.get()); + static constexpr auto exp = (1 + 2 + 3) + 4; + REQUIRE(res == exp); +} + + +TEST_CASE("Smoke static all settled", "[smoke]") +{ + std::vector funcs + { + [] (int val1, int val2, int val3) { return val1 + val2 + val3 + 4; }, + [] (int val1, int val2, int val3) { return val1 + val2 + val3 + 5; }, + [] (int val1, int val2, int val3) { return val1 + val2 + val3 + 6; }, + }; + + auto future = async::make_promise_all_settled(funcs, 1, 2, 3) + .then([] (const std::vector>& v) { return sum_settled(v); }) + .then([] (int val) { return val + 7; }) + .run(); + + auto res = 0; + REQUIRE_NOTHROW(res = future.get()); + static constexpr auto exp = (1 + 2 + 3 + 4) + (1 + 2 + 3 + 5) + (1 + 2 + 3 + 6) + 7; + REQUIRE(res == exp); +} + + +TEST_CASE("Smoke static all settled no args", "[smoke]") +{ + std::vector funcs + { + [] () { return 1; }, + [] () { return 2; }, + [] () { return 3; }, + }; + + auto future = async::make_promise_all_settled(funcs) + .then([] (const std::vector>& v) { return sum_settled(v); }) + .then([] (int val) { return val + 4; }) + .run(); + + auto res = 0; + REQUIRE_NOTHROW(res = future.get()); + static constexpr auto exp = (1 + 2 + 3) + 4; + REQUIRE(res == exp); +} + + +TEST_CASE("Smoke static any", "[smoke]") +{ + std::vector funcs + { + [] (int val1, int val2, int val3) { return val1 + val2 + val3 + 4; }, + [] (int val1, int val2, int val3) { return val1 + val2 + val3 + 4; }, + [] (int val1, int val2, int val3) { return val1 + val2 + val3 + 4; }, + }; + + auto future = async::make_promise_any(funcs, 1, 2, 3) + .then([] (int val) { return val + 5; }) + .run(); + + auto res = 0; + REQUIRE_NOTHROW(res = future.get()); + static constexpr auto exp = (1 + 2 + 3 + 4) + 5; + REQUIRE(res == exp); +} + + +TEST_CASE("Smoke static any no args", "[smoke]") +{ + std::vector funcs + { + [] () { return 1; }, + [] () { return 1; }, + [] () { return 1; }, + }; + + auto future = async::make_promise_any(funcs) + .then([] (int val) { return val + 2; }) + .run(); + + auto res = 0; + REQUIRE_NOTHROW(res = future.get()); + static constexpr auto exp = 1 + 2; + REQUIRE(res == exp); +} + + +TEST_CASE("Smoke static race", "[smoke]") +{ + std::vector funcs + { + [] (int val1, int val2, int val3) { return val1 + val2 + val3 + 4; }, + [] (int val1, int val2, int val3) { return val1 + val2 + val3 + 4; }, + [] (int val1, int val2, int val3) { return val1 + val2 + val3 + 4; }, + }; + + auto future = async::make_promise_race(funcs, 1, 2, 3) + .then([] (int val) { return val + 5; }) + .run(); + + auto res = 0; + REQUIRE_NOTHROW(res = future.get()); + static constexpr auto exp = (1 + 2 + 3 + 4) + 5; + REQUIRE(res == exp); +} + + +TEST_CASE("Smoke static race no args", "[smoke]") +{ + std::vector funcs + { + [] () { return 1; }, + [] () { return 1; }, + [] () { return 1; }, + }; + + auto future = async::make_promise_race(funcs) + .then([] (int val) { return val + 2; }) + .run(); + + auto res = 0; + REQUIRE_NOTHROW(res = future.get()); + static constexpr auto exp = 1 + 2; + REQUIRE(res == exp); +}