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]
|
[![language][badge.language]][language]
|
||||||
[![license][badge.license]][license]
|
[![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
|
[badge.license]: https://img.shields.io/badge/license-Apache--2.0-blue
|
||||||
|
|
||||||
[language]: https://en.wikipedia.org/wiki/C%2B%2B17
|
[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
|
# 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.
|
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=(const resume_token&) -> resume_token& = delete;
|
||||||
auto operator=(resume_token&&) -> resume_token& = default;
|
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:
|
private:
|
||||||
return_type m_result;
|
return_type m_return_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
@ -578,7 +578,7 @@ public:
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
co_return token.result();
|
co_return token.return_value();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -758,7 +758,7 @@ private:
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
co_return token.result();
|
co_return token.return_value();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -935,12 +935,12 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename return_type>
|
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);
|
void* old_value = m_state.exchange(this, std::memory_order::acq_rel);
|
||||||
if(old_value != this)
|
if(old_value != this)
|
||||||
{
|
{
|
||||||
m_result = std::move(result);
|
m_return_value = std::move(value);
|
||||||
|
|
||||||
auto* waiters = static_cast<awaiter*>(old_value);
|
auto* waiters = static_cast<awaiter*>(old_value);
|
||||||
while(waiters != nullptr)
|
while(waiters != nullptr)
|
||||||
|
|
|
@ -13,7 +13,7 @@ auto sync_wait(task_type&& task) -> decltype(auto)
|
||||||
{
|
{
|
||||||
task.resume();
|
task.resume();
|
||||||
}
|
}
|
||||||
return task.promise().result();
|
return task.promise().return_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ... tasks>
|
template<typename ... tasks>
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <atomic>
|
|
||||||
#include <coroutine>
|
#include <coroutine>
|
||||||
#include <optional>
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
namespace coro
|
namespace coro
|
||||||
{
|
{
|
||||||
|
@ -71,70 +67,70 @@ struct promise_base
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::coroutine_handle<> m_continuation{nullptr};
|
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>
|
template<typename return_type>
|
||||||
struct promise final : public promise_base
|
struct promise final : public promise_base
|
||||||
{
|
{
|
||||||
using task_type = task<return_type>;
|
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() noexcept = default;
|
||||||
~promise() = default;
|
~promise() = default;
|
||||||
|
|
||||||
auto get_return_object() noexcept -> task_type;
|
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:
|
private:
|
||||||
return_type m_result;
|
return_type m_return_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct promise<void> : public promise_base
|
struct promise<void> : public promise_base
|
||||||
{
|
{
|
||||||
using task_type = task<void>;
|
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() noexcept = default;
|
||||||
~promise() = default;
|
~promise() = default;
|
||||||
|
|
||||||
auto get_return_object() noexcept -> task_type;
|
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:
|
public:
|
||||||
using task_type = task<return_type>;
|
using task_type = task<return_type>;
|
||||||
using promise_type = detail::promise<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
|
struct awaitable_base
|
||||||
{
|
{
|
||||||
awaitable_base(std::coroutine_handle<promise_type> coroutine) noexcept
|
awaitable_base(coroutine_handle coroutine) noexcept
|
||||||
: m_coroutine(coroutine)
|
: m_coroutine(coroutine)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -177,7 +173,7 @@ public:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
task(coro_handle handle)
|
task(coroutine_handle handle)
|
||||||
: m_coroutine(handle)
|
: m_coroutine(handle)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -249,7 +245,7 @@ public:
|
||||||
{
|
{
|
||||||
auto await_resume() noexcept -> decltype(auto)
|
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());
|
return std::move(m_coroutine.promise());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto handle() -> coro_handle
|
auto handle() -> coroutine_handle
|
||||||
{
|
{
|
||||||
return m_coroutine;
|
return m_coroutine;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
coro_handle m_coroutine{nullptr};
|
coroutine_handle m_coroutine{nullptr};
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
|
@ -285,15 +281,14 @@ namespace detail
|
||||||
template<typename return_type>
|
template<typename return_type>
|
||||||
inline auto promise<return_type>::get_return_object() noexcept -> task<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<>
|
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 detail
|
||||||
|
|
||||||
|
|
||||||
} // namespace coro
|
} // namespace coro
|
||||||
|
|
|
@ -20,7 +20,7 @@ TEST_CASE("event single awaiter")
|
||||||
REQUIRE_FALSE(task.is_ready());
|
REQUIRE_FALSE(task.is_ready());
|
||||||
e.set(); // this will automaticaly resume the task that is awaiting the event.
|
e.set(); // this will automaticaly resume the task that is awaiting the event.
|
||||||
REQUIRE(task.is_ready());
|
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);
|
producer(e);
|
||||||
|
|
||||||
REQUIRE(value.promise().result() == 42);
|
REQUIRE(value.promise().return_value() == 42);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("event multiple watchers")
|
TEST_CASE("event multiple watchers")
|
||||||
|
@ -66,7 +66,7 @@ TEST_CASE("event multiple watchers")
|
||||||
|
|
||||||
producer(e);
|
producer(e);
|
||||||
|
|
||||||
REQUIRE(value1.promise().result() == 42);
|
REQUIRE(value1.promise().return_value() == 42);
|
||||||
REQUIRE(value2.promise().result() == 42);
|
REQUIRE(value2.promise().return_value() == 42);
|
||||||
REQUIRE(value3.promise().result() == 42);
|
REQUIRE(value3.promise().return_value() == 42);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ TEST_CASE("latch count=0")
|
||||||
|
|
||||||
task.resume();
|
task.resume();
|
||||||
REQUIRE(task.is_ready()); // The latch never waits due to zero count.
|
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")
|
TEST_CASE("latch count=1")
|
||||||
|
@ -37,7 +37,7 @@ TEST_CASE("latch count=1")
|
||||||
|
|
||||||
l.count_down();
|
l.count_down();
|
||||||
REQUIRE(task.is_ready());
|
REQUIRE(task.is_ready());
|
||||||
REQUIRE(task.promise().result() == 1);
|
REQUIRE(task.promise().return_value() == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("latch count=1 count_down=5")
|
TEST_CASE("latch count=1 count_down=5")
|
||||||
|
@ -56,7 +56,7 @@ TEST_CASE("latch count=1 count_down=5")
|
||||||
|
|
||||||
l.count_down(5);
|
l.count_down(5);
|
||||||
REQUIRE(task.is_ready());
|
REQUIRE(task.is_ready());
|
||||||
REQUIRE(task.promise().result() == 1);
|
REQUIRE(task.promise().return_value() == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("latch count=5 count_down=1 x5")
|
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());
|
REQUIRE_FALSE(task.is_ready());
|
||||||
l.count_down(1);
|
l.count_down(1);
|
||||||
REQUIRE(task.is_ready());
|
REQUIRE(task.is_ready());
|
||||||
REQUIRE(task.promise().result() == 5);
|
REQUIRE(task.promise().return_value() == 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("latch count=5 count_down=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);
|
l.count_down(5);
|
||||||
REQUIRE(task.is_ready());
|
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";
|
std::cerr << "1st suspend\n";
|
||||||
co_await s.yield(token);
|
co_await s.yield(token);
|
||||||
std::cerr << "1st resume\n";
|
std::cerr << "1st resume\n";
|
||||||
counter += token.result();
|
counter += token.return_value();
|
||||||
token.reset();
|
token.reset();
|
||||||
std::cerr << "never suspend\n";
|
std::cerr << "never suspend\n";
|
||||||
co_await std::suspend_never{};
|
co_await std::suspend_never{};
|
||||||
|
@ -105,12 +105,12 @@ TEST_CASE("scheduler task with multiple yields on event")
|
||||||
co_await s.yield(token);
|
co_await s.yield(token);
|
||||||
token.reset();
|
token.reset();
|
||||||
std::cerr << "2nd resume\n";
|
std::cerr << "2nd resume\n";
|
||||||
counter += token.result();
|
counter += token.return_value();
|
||||||
std::cerr << "3rd suspend\n";
|
std::cerr << "3rd suspend\n";
|
||||||
co_await s.yield(token);
|
co_await s.yield(token);
|
||||||
token.reset();
|
token.reset();
|
||||||
std::cerr << "3rd resume\n";
|
std::cerr << "3rd resume\n";
|
||||||
counter += token.result();
|
counter += token.return_value();
|
||||||
co_return;
|
co_return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -485,7 +485,7 @@ TEST_CASE("scheduler yield user event")
|
||||||
auto func = [&]() -> coro::task<void>
|
auto func = [&]() -> coro::task<void>
|
||||||
{
|
{
|
||||||
co_await s.yield(token);
|
co_await s.yield(token);
|
||||||
REQUIRE(token.result() == expected_result);
|
REQUIRE(token.return_value() == expected_result);
|
||||||
co_return;
|
co_return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -551,4 +551,22 @@ TEST_CASE("scheduler manual process events with self generating coroutine (stack
|
||||||
|
|
||||||
while(s.process_events()) ;
|
while(s.process_events()) ;
|
||||||
std::cerr << "Recursive test done.\n";
|
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 h = []() -> task_type { co_return "Hello"; }();
|
||||||
auto w = []() -> task_type { co_return "World"; }();
|
auto w = []() -> task_type { co_return "World"; }();
|
||||||
|
|
||||||
REQUIRE(h.promise().result().empty());
|
REQUIRE(h.promise().return_value().empty());
|
||||||
REQUIRE(w.promise().result().empty());
|
REQUIRE(w.promise().return_value().empty());
|
||||||
|
|
||||||
h.resume(); // task suspends immediately
|
h.resume(); // task suspends immediately
|
||||||
w.resume();
|
w.resume();
|
||||||
|
@ -22,11 +22,11 @@ TEST_CASE("task hello world")
|
||||||
REQUIRE(h.is_ready());
|
REQUIRE(h.is_ready());
|
||||||
REQUIRE(w.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_value == "World");
|
||||||
REQUIRE(w.promise().result().empty());
|
REQUIRE(w.promise().return_value().empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("task void")
|
TEST_CASE("task void")
|
||||||
|
@ -61,7 +61,7 @@ TEST_CASE("task exception thrown")
|
||||||
bool thrown{false};
|
bool thrown{false};
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
auto value = task.promise().result();
|
auto value = task.promise().return_value();
|
||||||
}
|
}
|
||||||
catch(const std::exception& e)
|
catch(const std::exception& e)
|
||||||
{
|
{
|
||||||
|
@ -172,7 +172,7 @@ TEST_CASE("task multiple suspends return integer")
|
||||||
|
|
||||||
task.resume(); // third internal suspend
|
task.resume(); // third internal suspend
|
||||||
REQUIRE(task.is_ready());
|
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")
|
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(task1.is_ready());
|
||||||
REQUIRE(coro_handle1.done());
|
REQUIRE(coro_handle1.done());
|
||||||
REQUIRE(task1.promise().result() == 42);
|
REQUIRE(task1.promise().return_value() == 42);
|
||||||
|
|
||||||
REQUIRE(task2.is_ready());
|
REQUIRE(task2.is_ready());
|
||||||
REQUIRE(coro_handle2.done());
|
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