diff options
Diffstat (limited to 'src/spawn/test/test_exception.cc')
-rw-r--r-- | src/spawn/test/test_exception.cc | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/src/spawn/test/test_exception.cc b/src/spawn/test/test_exception.cc new file mode 100644 index 000000000..5dea81bad --- /dev/null +++ b/src/spawn/test/test_exception.cc @@ -0,0 +1,142 @@ +// +// test_exception.cpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2020 Casey Bodley (cbodley at redhat dot com) +// +// Distributed under 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) +// + +#include <spawn/spawn.hpp> + +#include <boost/asio/io_context.hpp> +#include <boost/asio/post.hpp> +#include <gtest/gtest.h> + + +struct throwing_handler { + template <typename T> + void operator()(spawn::basic_yield_context<T>) { + throw std::runtime_error(""); + } +}; + +TEST(Exception, SpawnThrowInHelper) +{ + boost::asio::io_context ioc; + spawn::spawn(ioc, throwing_handler()); + EXPECT_THROW(ioc.run_one(), std::runtime_error); // spawn->throw +} + +struct noop_handler { + template <typename T> + void operator()(spawn::basic_yield_context<T>) {} +}; + +struct throwing_completion_handler { + void operator()() { + throw std::runtime_error(""); + } +}; + +TEST(Exception, SpawnHandlerThrowInHelper) +{ + boost::asio::io_context ioc; + spawn::spawn(bind_executor(ioc.get_executor(), + throwing_completion_handler()), + noop_handler()); + EXPECT_THROW(ioc.run_one(), std::runtime_error); // spawn->throw +} + +template <typename CompletionToken> +auto async_yield(CompletionToken&& token) + -> BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) +{ + boost::asio::async_completion<CompletionToken, void()> init(token); + boost::asio::post(std::move(init.completion_handler)); + return init.result.get(); +} + +struct yield_throwing_handler { + template <typename T> + void operator()(spawn::basic_yield_context<T> y) { + async_yield(y); // suspend and resume before throwing + throw std::runtime_error(""); + } +}; + +TEST(Exception, SpawnThrowAfterYield) +{ + boost::asio::io_context ioc; + spawn::spawn(ioc, yield_throwing_handler()); + ASSERT_NO_THROW(ioc.run_one()); // yield_throwing_handler suspend + EXPECT_THROW(ioc.run_one(), std::runtime_error); // resume + throw +} + +struct yield_handler { + template <typename T> + void operator()(spawn::basic_yield_context<T> y) { + async_yield(y); + } +}; + +TEST(Exception, SpawnHandlerThrowAfterYield) +{ + boost::asio::io_context ioc; + spawn::spawn(bind_executor(ioc.get_executor(), + throwing_completion_handler()), + yield_handler()); + ASSERT_NO_THROW(ioc.run_one()); // yield_handler suspend + EXPECT_THROW(ioc.run_one(), std::runtime_error); // resume + throw +} + +struct nested_throwing_handler { + template <typename T> + void operator()(spawn::basic_yield_context<T> y) { + spawn::spawn(y, throwing_handler()); + } +}; + +TEST(Exception, SpawnThrowInNestedHelper) +{ + boost::asio::io_context ioc; + spawn::spawn(ioc, nested_throwing_handler()); + EXPECT_THROW(ioc.run_one(), std::runtime_error); // spawn->spawn->throw +} + +struct yield_nested_throwing_handler { + template <typename T> + void operator()(spawn::basic_yield_context<T> y) { + async_yield(y); // suspend and resume before spawning + spawn::spawn(y, yield_throwing_handler()); + } +}; + +TEST(Exception, SpawnThrowAfterNestedYield) +{ + boost::asio::io_context ioc; + spawn::spawn(ioc, yield_nested_throwing_handler()); + ASSERT_NO_THROW(ioc.run_one()); // yield_nested_throwing_handler suspend + ASSERT_NO_THROW(ioc.run_one()); // yield_throwing_handler suspend + EXPECT_THROW(ioc.run_one(), std::runtime_error); // resume + throw +} + +struct yield_throw_after_nested_handler { + template <typename T> + void operator()(spawn::basic_yield_context<T> y) { + async_yield(y); // suspend and resume before spawning + spawn::spawn(y, yield_handler()); + throw std::runtime_error(""); + } +}; + +TEST(Exception, SpawnThrowAfterNestedSpawn) +{ + boost::asio::io_context ioc; + spawn::spawn(ioc, yield_throw_after_nested_handler()); + ASSERT_NO_THROW(ioc.run_one()); // yield_throw_after_nested_handler suspend + EXPECT_THROW(ioc.run_one(), std::runtime_error); // resume + throw + EXPECT_EQ(1, ioc.poll()); // yield_handler resume + EXPECT_TRUE(ioc.stopped()); +} |