mirror of
https://gitlab.com/niansa/libcrosscoro.git
synced 2025-03-06 20:53:32 +01:00
Add tests for tasks that throw (#4)
* Add tests for tasks that throw * Additional task types for throwing coverage
This commit is contained in:
parent
31dded8611
commit
1a2ec073ca
12 changed files with 268 additions and 65 deletions
67
.clang-format
Normal file
67
.clang-format
Normal file
|
@ -0,0 +1,67 @@
|
|||
---
|
||||
AlignAfterOpenBracket: AlwaysBreak
|
||||
AlignConsecutiveMacros: 'true'
|
||||
AlignConsecutiveAssignments: 'true'
|
||||
AlignConsecutiveDeclarations: 'true'
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: 'true'
|
||||
AlignTrailingComments: 'true'
|
||||
AllowAllArgumentsOnNextLine: 'true'
|
||||
AllowAllConstructorInitializersOnNextLine: 'false'
|
||||
AllowAllParametersOfDeclarationOnNextLine: 'true'
|
||||
AllowShortBlocksOnASingleLine: 'true'
|
||||
AllowShortCaseLabelsOnASingleLine: 'false'
|
||||
AllowShortFunctionsOnASingleLine: InlineOnly
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortLoopsOnASingleLine: 'false'
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: 'true'
|
||||
AlwaysBreakTemplateDeclarations: 'Yes'
|
||||
BinPackArguments: 'false'
|
||||
BinPackParameters: 'false'
|
||||
BreakAfterJavaFieldAnnotations: 'true'
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Allman
|
||||
BreakBeforeTernaryOperators: 'true'
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakStringLiterals: 'false'
|
||||
ColumnLimit: '120'
|
||||
CompactNamespaces: 'false'
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: 'true'
|
||||
ConstructorInitializerIndentWidth: '4'
|
||||
ContinuationIndentWidth: '4'
|
||||
Cpp11BracedListStyle: 'true'
|
||||
FixNamespaceComments: 'true'
|
||||
IncludeBlocks: Preserve
|
||||
IndentCaseLabels: 'true'
|
||||
IndentPPDirectives: BeforeHash
|
||||
IndentWidth: '4'
|
||||
IndentWrappedFunctionNames: 'true'
|
||||
KeepEmptyLinesAtTheStartOfBlocks: 'false'
|
||||
Language: Cpp
|
||||
MaxEmptyLinesToKeep: '1'
|
||||
NamespaceIndentation: None
|
||||
PointerAlignment: Left
|
||||
ReflowComments: 'true'
|
||||
SortIncludes: 'true'
|
||||
SortUsingDeclarations: 'true'
|
||||
SpaceAfterCStyleCast: 'false'
|
||||
SpaceAfterLogicalNot: 'false'
|
||||
SpaceAfterTemplateKeyword: 'false'
|
||||
SpaceBeforeAssignmentOperators: 'true'
|
||||
SpaceBeforeCpp11BracedList: 'false'
|
||||
SpaceBeforeCtorInitializerColon: 'true'
|
||||
SpaceBeforeInheritanceColon: 'true'
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: 'true'
|
||||
SpaceInEmptyParentheses: 'false'
|
||||
SpacesInAngles: 'false'
|
||||
SpacesInCStyleCastParentheses: 'false'
|
||||
SpacesInContainerLiterals: 'false'
|
||||
SpacesInParentheses: 'false'
|
||||
SpacesInSquareBrackets: 'false'
|
||||
Standard: Cpp11
|
||||
UseTab: Never
|
||||
...
|
56
Makefile
Normal file
56
Makefile
Normal file
|
@ -0,0 +1,56 @@
|
|||
.DEFAULT_GOAL := debug
|
||||
|
||||
# Builds the project and tests in the Debug directory.
|
||||
debug:
|
||||
@$(MAKE) compile BUILD_TYPE=Debug --no-print-directory
|
||||
|
||||
# Builds the project and tests in the RelWithDebInfo directory.
|
||||
release-with-debug-info:
|
||||
@$(MAKE) compile BUILD_TYPE=RelWithDebInfo --no-print-directory
|
||||
|
||||
# Builds the project and tests in the Release directory.
|
||||
release:
|
||||
@$(MAKE) compile BUILD_TYPE=Release --no-print-directory
|
||||
|
||||
# Internal target for all build targets to call.
|
||||
compile:
|
||||
mkdir -p ${BUILD_TYPE}; \
|
||||
cd ${BUILD_TYPE}; \
|
||||
cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} ..; \
|
||||
cmake --build . -- -j $(nproc)
|
||||
|
||||
# Run Debug tests.
|
||||
debug-test:
|
||||
@$(MAKE) test BUILD_TYPE=Debug --no-print-directory
|
||||
|
||||
# Run RelWithDebInfo tests.
|
||||
release-with-debug-info-test:
|
||||
@$(MAKE) test BUILD_TYPE=RelWithDebInfo --no-print-directory
|
||||
|
||||
# Run Release tests.
|
||||
release-test:
|
||||
@$(MAKE) test BUILD_TYPE=Release --no-print-directory
|
||||
|
||||
# Internal target for all test targets to call.
|
||||
.PHONY: test
|
||||
test:
|
||||
cd ${BUILD_TYPE}; \
|
||||
ctest -VV
|
||||
|
||||
# Cleans all build types.
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf Debug
|
||||
rm -rf RelWithDebInfo
|
||||
rm -rf Release
|
||||
|
||||
# Runs clang-format with the project's .clang-format.
|
||||
format:
|
||||
# Inlcude *.hpp|*.h|*.cpp but ignore catch lib as well as RelWithDebInfo|Release|Debug|build
|
||||
find . \( -name '*.hpp' -or -name '*.h' -or -name '*.cpp' \) \
|
||||
-and -not -name '*catch*' \
|
||||
-and -not -iwholename '*/RelWithDebInfo/*' \
|
||||
-and -not -iwholename '*/Release/*' \
|
||||
-and -not -iwholename '*/Debug/*' \
|
||||
-and -not -iwholename '*/build/*' \
|
||||
-exec clang-format -i --style=file {} \;
|
19
README.md
19
README.md
|
@ -6,7 +6,7 @@ libcoro C++20 Coroutines
|
|||
[![language][badge.language]][language]
|
||||
[![license][badge.license]][license]
|
||||
|
||||
[badge.language]: https://img.shields.io/badge/language-C%2B%2B17-yellow.svg
|
||||
[badge.language]: https://img.shields.io/badge/language-C%2B%2B20-yellow.svg
|
||||
[badge.license]: https://img.shields.io/badge/license-Apache--2.0-blue
|
||||
|
||||
[language]: https://en.wikipedia.org/wiki/C%2B%2B17
|
||||
|
@ -19,3 +19,20 @@ Libcoro is a C++20 coroutine library. So far most inspiration has been gleaned
|
|||
|
||||
# Goal
|
||||
Libcoro is currently more of a learning experience for myself but ultimately I'd like to turn this into a great linux coroutine base library with an easy to use HTTP scheduler/server.
|
||||
|
||||
# Building
|
||||
There is a root makefile with various commands to help make building and running tests on this project easier.
|
||||
|
||||
```bash
|
||||
# Build targets
|
||||
make debug|release-with-debug-info|release
|
||||
|
||||
# Run tests targets
|
||||
make debug-test|release-with-debug-info-tests|release-tests
|
||||
|
||||
# Clean all builds.
|
||||
make clean
|
||||
|
||||
# clang-format the code
|
||||
make format
|
||||
```
|
||||
|
|
1
Testing/Temporary/CTestCostData.txt
Normal file
1
Testing/Temporary/CTestCostData.txt
Normal file
|
@ -0,0 +1 @@
|
|||
---
|
3
Testing/Temporary/LastTest.log
Normal file
3
Testing/Temporary/LastTest.log
Normal file
|
@ -0,0 +1,3 @@
|
|||
Start testing: Oct 12 14:19 MST
|
||||
----------------------------------------------------------
|
||||
End testing: Oct 12 14:19 MST
|
|
@ -162,19 +162,19 @@ public:
|
|||
auto operator=(const resume_token&) -> resume_token& = delete;
|
||||
auto operator=(resume_token&&) -> resume_token& = default;
|
||||
|
||||
auto resume(return_type result) noexcept -> void;
|
||||
auto resume(return_type value) noexcept -> void;
|
||||
|
||||
auto result() const & -> const return_type&
|
||||
auto return_value() const & -> const return_type&
|
||||
{
|
||||
return m_result;
|
||||
return m_return_value;
|
||||
}
|
||||
|
||||
auto result() && -> return_type&&
|
||||
auto return_value() && -> return_type&&
|
||||
{
|
||||
return std::move(m_result);
|
||||
return std::move(m_return_value);
|
||||
}
|
||||
private:
|
||||
return_type m_result;
|
||||
return_type m_return_value;
|
||||
};
|
||||
|
||||
template<>
|
||||
|
@ -578,7 +578,7 @@ public:
|
|||
}
|
||||
else
|
||||
{
|
||||
co_return token.result();
|
||||
co_return token.return_value();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -758,7 +758,7 @@ private:
|
|||
}
|
||||
else
|
||||
{
|
||||
co_return token.result();
|
||||
co_return token.return_value();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -935,12 +935,12 @@ private:
|
|||
};
|
||||
|
||||
template<typename return_type>
|
||||
inline auto resume_token<return_type>::resume(return_type result) noexcept -> void
|
||||
inline auto resume_token<return_type>::resume(return_type value) noexcept -> void
|
||||
{
|
||||
void* old_value = m_state.exchange(this, std::memory_order::acq_rel);
|
||||
if(old_value != this)
|
||||
{
|
||||
m_result = std::move(result);
|
||||
m_return_value = std::move(value);
|
||||
|
||||
auto* waiters = static_cast<awaiter*>(old_value);
|
||||
while(waiters != nullptr)
|
||||
|
|
|
@ -13,7 +13,7 @@ auto sync_wait(task_type&& task) -> decltype(auto)
|
|||
{
|
||||
task.resume();
|
||||
}
|
||||
return task.promise().result();
|
||||
return task.promise().return_value();
|
||||
}
|
||||
|
||||
template<typename ... tasks>
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <coroutine>
|
||||
#include <optional>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace coro
|
||||
{
|
||||
|
@ -71,70 +67,70 @@ struct promise_base
|
|||
|
||||
protected:
|
||||
std::coroutine_handle<> m_continuation{nullptr};
|
||||
std::optional<std::exception_ptr> m_exception_ptr{std::nullopt};
|
||||
std::exception_ptr m_exception_ptr{};
|
||||
};
|
||||
|
||||
template<typename return_type>
|
||||
struct promise final : public promise_base
|
||||
{
|
||||
using task_type = task<return_type>;
|
||||
using coro_handle = std::coroutine_handle<promise<return_type>>;
|
||||
using coroutine_handle = std::coroutine_handle<promise<return_type>>;
|
||||
|
||||
promise() noexcept = default;
|
||||
~promise() = default;
|
||||
|
||||
auto get_return_object() noexcept -> task_type;
|
||||
|
||||
auto return_value(return_type result) -> void
|
||||
auto return_value(return_type value) -> void
|
||||
{
|
||||
m_result = std::move(result);
|
||||
m_return_value = std::move(value);
|
||||
}
|
||||
|
||||
auto result() const & -> const return_type&
|
||||
auto return_value() const & -> const return_type&
|
||||
{
|
||||
if(this->m_exception_ptr.has_value())
|
||||
if(m_exception_ptr)
|
||||
{
|
||||
std::rethrow_exception(this->m_exception_ptr.value());
|
||||
std::rethrow_exception(m_exception_ptr);
|
||||
}
|
||||
|
||||
return m_result;
|
||||
return m_return_value;
|
||||
}
|
||||
|
||||
auto result() && -> return_type&&
|
||||
auto return_value() && -> return_type&&
|
||||
{
|
||||
if(this->m_exception_ptr.has_value())
|
||||
if(m_exception_ptr)
|
||||
{
|
||||
std::rethrow_exception(this->m_exception_ptr.value());
|
||||
std::rethrow_exception(m_exception_ptr);
|
||||
}
|
||||
|
||||
return std::move(m_result);
|
||||
return std::move(m_return_value);
|
||||
}
|
||||
|
||||
private:
|
||||
return_type m_result;
|
||||
return_type m_return_value;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct promise<void> : public promise_base
|
||||
{
|
||||
using task_type = task<void>;
|
||||
using coro_handle = std::coroutine_handle<promise<void>>;
|
||||
using coroutine_handle = std::coroutine_handle<promise<void>>;
|
||||
|
||||
promise() noexcept = default;
|
||||
~promise() = default;
|
||||
|
||||
auto get_return_object() noexcept -> task_type;
|
||||
|
||||
auto return_void() -> void
|
||||
auto return_void() noexcept -> void
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
auto result() const -> void
|
||||
auto return_value() const -> void
|
||||
{
|
||||
if(this->m_exception_ptr.has_value())
|
||||
if(m_exception_ptr)
|
||||
{
|
||||
std::rethrow_exception(this->m_exception_ptr.value());
|
||||
std::rethrow_exception(m_exception_ptr);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -147,11 +143,11 @@ class task
|
|||
public:
|
||||
using task_type = task<return_type>;
|
||||
using promise_type = detail::promise<return_type>;
|
||||
using coro_handle = std::coroutine_handle<promise_type>;
|
||||
using coroutine_handle = std::coroutine_handle<promise_type>;
|
||||
|
||||
struct awaitable_base
|
||||
{
|
||||
awaitable_base(std::coroutine_handle<promise_type> coroutine) noexcept
|
||||
awaitable_base(coroutine_handle coroutine) noexcept
|
||||
: m_coroutine(coroutine)
|
||||
{
|
||||
|
||||
|
@ -177,7 +173,7 @@ public:
|
|||
|
||||
}
|
||||
|
||||
task(coro_handle handle)
|
||||
task(coroutine_handle handle)
|
||||
: m_coroutine(handle)
|
||||
{
|
||||
|
||||
|
@ -249,7 +245,7 @@ public:
|
|||
{
|
||||
auto await_resume() noexcept -> decltype(auto)
|
||||
{
|
||||
return this->m_coroutine.promise().result();
|
||||
return this->m_coroutine.promise().return_value();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -270,13 +266,13 @@ public:
|
|||
return std::move(m_coroutine.promise());
|
||||
}
|
||||
|
||||
auto handle() -> coro_handle
|
||||
auto handle() -> coroutine_handle
|
||||
{
|
||||
return m_coroutine;
|
||||
}
|
||||
|
||||
private:
|
||||
coro_handle m_coroutine{nullptr};
|
||||
coroutine_handle m_coroutine{nullptr};
|
||||
};
|
||||
|
||||
namespace detail
|
||||
|
@ -285,15 +281,14 @@ namespace detail
|
|||
template<typename return_type>
|
||||
inline auto promise<return_type>::get_return_object() noexcept -> task<return_type>
|
||||
{
|
||||
return task<return_type>{coro_handle::from_promise(*this)};
|
||||
return task<return_type>{coroutine_handle::from_promise(*this)};
|
||||
}
|
||||
|
||||
inline auto promise<void>::get_return_object() noexcept -> task<>
|
||||
{
|
||||
return task<>{coro_handle::from_promise(*this)};
|
||||
return task<>{coroutine_handle::from_promise(*this)};
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
||||
} // namespace coro
|
||||
|
|
|
@ -20,7 +20,7 @@ TEST_CASE("event single awaiter")
|
|||
REQUIRE_FALSE(task.is_ready());
|
||||
e.set(); // this will automaticaly resume the task that is awaiting the event.
|
||||
REQUIRE(task.is_ready());
|
||||
REQUIRE(task.promise().result() == 42);
|
||||
REQUIRE(task.promise().return_value() == 42);
|
||||
}
|
||||
|
||||
|
||||
|
@ -47,7 +47,7 @@ TEST_CASE("event one watcher")
|
|||
|
||||
producer(e);
|
||||
|
||||
REQUIRE(value.promise().result() == 42);
|
||||
REQUIRE(value.promise().return_value() == 42);
|
||||
}
|
||||
|
||||
TEST_CASE("event multiple watchers")
|
||||
|
@ -66,7 +66,7 @@ TEST_CASE("event multiple watchers")
|
|||
|
||||
producer(e);
|
||||
|
||||
REQUIRE(value1.promise().result() == 42);
|
||||
REQUIRE(value2.promise().result() == 42);
|
||||
REQUIRE(value3.promise().result() == 42);
|
||||
REQUIRE(value1.promise().return_value() == 42);
|
||||
REQUIRE(value2.promise().return_value() == 42);
|
||||
REQUIRE(value3.promise().return_value() == 42);
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ TEST_CASE("latch count=0")
|
|||
|
||||
task.resume();
|
||||
REQUIRE(task.is_ready()); // The latch never waits due to zero count.
|
||||
REQUIRE(task.promise().result() == 42);
|
||||
REQUIRE(task.promise().return_value() == 42);
|
||||
}
|
||||
|
||||
TEST_CASE("latch count=1")
|
||||
|
@ -37,7 +37,7 @@ TEST_CASE("latch count=1")
|
|||
|
||||
l.count_down();
|
||||
REQUIRE(task.is_ready());
|
||||
REQUIRE(task.promise().result() == 1);
|
||||
REQUIRE(task.promise().return_value() == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("latch count=1 count_down=5")
|
||||
|
@ -56,7 +56,7 @@ TEST_CASE("latch count=1 count_down=5")
|
|||
|
||||
l.count_down(5);
|
||||
REQUIRE(task.is_ready());
|
||||
REQUIRE(task.promise().result() == 1);
|
||||
REQUIRE(task.promise().return_value() == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("latch count=5 count_down=1 x5")
|
||||
|
@ -83,7 +83,7 @@ TEST_CASE("latch count=5 count_down=1 x5")
|
|||
REQUIRE_FALSE(task.is_ready());
|
||||
l.count_down(1);
|
||||
REQUIRE(task.is_ready());
|
||||
REQUIRE(task.promise().result() == 5);
|
||||
REQUIRE(task.promise().return_value() == 5);
|
||||
}
|
||||
|
||||
TEST_CASE("latch count=5 count_down=5")
|
||||
|
@ -102,5 +102,5 @@ TEST_CASE("latch count=5 count_down=5")
|
|||
|
||||
l.count_down(5);
|
||||
REQUIRE(task.is_ready());
|
||||
REQUIRE(task.promise().result() == 5);
|
||||
REQUIRE(task.promise().return_value() == 5);
|
||||
}
|
||||
|
|
|
@ -97,7 +97,7 @@ TEST_CASE("scheduler task with multiple yields on event")
|
|||
std::cerr << "1st suspend\n";
|
||||
co_await s.yield(token);
|
||||
std::cerr << "1st resume\n";
|
||||
counter += token.result();
|
||||
counter += token.return_value();
|
||||
token.reset();
|
||||
std::cerr << "never suspend\n";
|
||||
co_await std::suspend_never{};
|
||||
|
@ -105,12 +105,12 @@ TEST_CASE("scheduler task with multiple yields on event")
|
|||
co_await s.yield(token);
|
||||
token.reset();
|
||||
std::cerr << "2nd resume\n";
|
||||
counter += token.result();
|
||||
counter += token.return_value();
|
||||
std::cerr << "3rd suspend\n";
|
||||
co_await s.yield(token);
|
||||
token.reset();
|
||||
std::cerr << "3rd resume\n";
|
||||
counter += token.result();
|
||||
counter += token.return_value();
|
||||
co_return;
|
||||
};
|
||||
|
||||
|
@ -485,7 +485,7 @@ TEST_CASE("scheduler yield user event")
|
|||
auto func = [&]() -> coro::task<void>
|
||||
{
|
||||
co_await s.yield(token);
|
||||
REQUIRE(token.result() == expected_result);
|
||||
REQUIRE(token.return_value() == expected_result);
|
||||
co_return;
|
||||
};
|
||||
|
||||
|
@ -551,4 +551,22 @@ TEST_CASE("scheduler manual process events with self generating coroutine (stack
|
|||
|
||||
while(s.process_events()) ;
|
||||
std::cerr << "Recursive test done.\n";
|
||||
}
|
||||
|
||||
TEST_CASE("scheduler task throws")
|
||||
{
|
||||
coro::scheduler s{};
|
||||
|
||||
auto func = []() -> coro::task<void>
|
||||
{
|
||||
// Is it possible to actually notify the user when running a task in a scheduler?
|
||||
// Seems like the user will need to manually catch.
|
||||
throw std::runtime_error{"I always throw."};
|
||||
co_return;
|
||||
};
|
||||
|
||||
s.schedule(func());
|
||||
|
||||
s.shutdown();
|
||||
REQUIRE(s.empty());
|
||||
}
|
|
@ -13,8 +13,8 @@ TEST_CASE("task hello world")
|
|||
auto h = []() -> task_type { co_return "Hello"; }();
|
||||
auto w = []() -> task_type { co_return "World"; }();
|
||||
|
||||
REQUIRE(h.promise().result().empty());
|
||||
REQUIRE(w.promise().result().empty());
|
||||
REQUIRE(h.promise().return_value().empty());
|
||||
REQUIRE(w.promise().return_value().empty());
|
||||
|
||||
h.resume(); // task suspends immediately
|
||||
w.resume();
|
||||
|
@ -22,11 +22,11 @@ TEST_CASE("task hello world")
|
|||
REQUIRE(h.is_ready());
|
||||
REQUIRE(w.is_ready());
|
||||
|
||||
auto w_value = std::move(w).promise().result();
|
||||
auto w_value = std::move(w).promise().return_value();
|
||||
|
||||
REQUIRE(h.promise().result() == "Hello");
|
||||
REQUIRE(h.promise().return_value() == "Hello");
|
||||
REQUIRE(w_value == "World");
|
||||
REQUIRE(w.promise().result().empty());
|
||||
REQUIRE(w.promise().return_value().empty());
|
||||
}
|
||||
|
||||
TEST_CASE("task void")
|
||||
|
@ -61,7 +61,7 @@ TEST_CASE("task exception thrown")
|
|||
bool thrown{false};
|
||||
try
|
||||
{
|
||||
auto value = task.promise().result();
|
||||
auto value = task.promise().return_value();
|
||||
}
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
|
@ -172,7 +172,7 @@ TEST_CASE("task multiple suspends return integer")
|
|||
|
||||
task.resume(); // third internal suspend
|
||||
REQUIRE(task.is_ready());
|
||||
REQUIRE(task.promise().result() == 11);
|
||||
REQUIRE(task.promise().return_value() == 11);
|
||||
}
|
||||
|
||||
TEST_CASE("task resume from promise to coroutine handles of different types")
|
||||
|
@ -203,8 +203,54 @@ TEST_CASE("task resume from promise to coroutine handles of different types")
|
|||
|
||||
REQUIRE(task1.is_ready());
|
||||
REQUIRE(coro_handle1.done());
|
||||
REQUIRE(task1.promise().result() == 42);
|
||||
REQUIRE(task1.promise().return_value() == 42);
|
||||
|
||||
REQUIRE(task2.is_ready());
|
||||
REQUIRE(coro_handle2.done());
|
||||
}
|
||||
|
||||
TEST_CASE("task throws void")
|
||||
{
|
||||
auto task = []() -> coro::task<void>
|
||||
{
|
||||
throw std::runtime_error{"I always throw."};
|
||||
co_return;
|
||||
}();
|
||||
|
||||
task.resume();
|
||||
REQUIRE(task.is_ready());
|
||||
REQUIRE_THROWS_AS(task.promise().return_value(), std::runtime_error);
|
||||
}
|
||||
|
||||
TEST_CASE("task throws non-void l-value")
|
||||
{
|
||||
auto task = []() -> coro::task<int>
|
||||
{
|
||||
throw std::runtime_error{"I always throw."};
|
||||
co_return 42;
|
||||
}();
|
||||
|
||||
task.resume();
|
||||
REQUIRE(task.is_ready());
|
||||
REQUIRE_THROWS_AS(task.promise().return_value(), std::runtime_error);
|
||||
}
|
||||
|
||||
TEST_CASE("task throws non-void r-value")
|
||||
{
|
||||
struct type
|
||||
{
|
||||
int m_value;
|
||||
};
|
||||
|
||||
auto task = []() -> coro::task<type>
|
||||
{
|
||||
type return_value{42};
|
||||
|
||||
throw std::runtime_error{"I always throw."};
|
||||
co_return std::move(return_value);
|
||||
}();
|
||||
|
||||
task.resume();
|
||||
REQUIRE(task.is_ready());
|
||||
REQUIRE_THROWS_AS(task.promise().return_value(), std::runtime_error);
|
||||
}
|
Loading…
Add table
Reference in a new issue