mirror of
https://github.com/Naios/continuable.git
synced 2026-01-01 03:12:12 +08:00
Start to implement the unit tests for loop and add range_loop
This commit is contained in:
parent
135ebfccf3
commit
ac175b4e57
@ -37,9 +37,14 @@
|
||||
#include <type_traits>
|
||||
#include <continuable/continuable-base.hpp>
|
||||
#include <continuable/continuable-result.hpp>
|
||||
#include <continuable/detail/features.hpp>
|
||||
#include <continuable/detail/utility/traits.hpp>
|
||||
#include <continuable/detail/utility/util.hpp>
|
||||
|
||||
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||
#include <exception>
|
||||
#endif // CONTINUABLE_HAS_EXCEPTIONS
|
||||
|
||||
namespace cti {
|
||||
namespace detail {
|
||||
template <typename T>
|
||||
@ -74,24 +79,52 @@ class loop_frame : public std::enable_shared_from_this<
|
||||
ArgsTuple args_;
|
||||
|
||||
public:
|
||||
explicit loop_frame(Promise promise, Callable callable, ArgsTuple args)
|
||||
: promise_(std::move(promise)), callable_(std::move(callable)),
|
||||
args_(std::move(args)) {
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// MSVC can't evaluate this inside the lambda capture
|
||||
auto me = this->shared_from_this();
|
||||
|
||||
traits::unpack(
|
||||
[&callable_](auto&&... args) {
|
||||
util::invoke(callable_, std::forward<decltype(args)>(args)...)
|
||||
.then([me = this->shared_from_this()](auto&& result) {
|
||||
if (result.is_empty()) {
|
||||
me->loop();
|
||||
} else if (result.is_value()) {
|
||||
traits::unpack(std::move(promise_), result);
|
||||
} else {
|
||||
assert(result.is_exception());
|
||||
traits::unpack(std::move(promise_), exception_arg_t{},
|
||||
result.get_exception());
|
||||
}
|
||||
});
|
||||
[&](auto&&... args) mutable {
|
||||
|
||||
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||
try {
|
||||
#endif // CONTINUABLE_HAS_EXCEPTIONS
|
||||
|
||||
util::invoke(callable_, std::forward<decltype(args)>(args)...)
|
||||
.next([me = std::move(me)](auto&&... args) {
|
||||
me->resolve(std::forward<decltype(args)>(args)...);
|
||||
});
|
||||
|
||||
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||
} catch (...) {
|
||||
resolve(exception_arg_t{}, std::current_exception());
|
||||
}
|
||||
#endif // CONTINUABLE_HAS_EXCEPTIONS
|
||||
},
|
||||
args_);
|
||||
}
|
||||
|
||||
template <typename Result>
|
||||
void resolve(Result&& result) {
|
||||
if (result.is_empty()) {
|
||||
loop();
|
||||
} else if (result.is_value()) {
|
||||
traits::unpack(std::move(promise_), std::forward<Result>(result));
|
||||
} else {
|
||||
assert(result.is_exception());
|
||||
std::move(promise_).set_exception(
|
||||
std::forward<Result>(result).get_exception());
|
||||
}
|
||||
}
|
||||
|
||||
void resolve(exception_arg_t, exception_t exception) {
|
||||
promise_.set_exception(std::move(exception));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Promise, typename Callable, typename ArgsTuple>
|
||||
@ -115,10 +148,27 @@ auto loop(Callable&& callable, Args&&... args) {
|
||||
args = std::make_tuple(std::forward<decltype(args)>(
|
||||
args)...)](auto&& promise) mutable {
|
||||
// Do the actual looping
|
||||
auto frame = make_loop_frame(std::forward<decltype(promise)>(promise));
|
||||
auto frame = make_loop_frame(std::forward<decltype(promise)>(promise),
|
||||
std::move(callable), std::move(args));
|
||||
frame->loop();
|
||||
});
|
||||
}
|
||||
|
||||
template <typename Callable, typename Begin>
|
||||
auto make_range_looper(Callable&& callable, Begin&& begin) {
|
||||
return [callable = std::forward<Callable>(callable),
|
||||
begin = std::forward<Begin>(begin)](auto&& end) mutable {
|
||||
return util::invoke(callable, begin)
|
||||
.then([&begin, // begin stays valid over the `then`.
|
||||
end = std::forward<decltype(end)>(end)]() mutable -> result<> {
|
||||
if (++begin != end) {
|
||||
return empty_result{};
|
||||
} else {
|
||||
return make_result();
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
} // namespace operations
|
||||
} // namespace detail
|
||||
} // namespace cti
|
||||
|
||||
@ -37,12 +37,18 @@
|
||||
namespace cti {
|
||||
/// \ingroup Operations
|
||||
/// \{
|
||||
|
||||
template <typename Callable, typename... Args>
|
||||
auto loop(Callable&& callable, Args&&... args) {
|
||||
return detail::operations::loop(std::forward<Callable>(callable),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename Callable, typename Iterator>
|
||||
auto range_loop(Callable&& callable, Iterator begin, Iterator end) {
|
||||
auto looper = detail::operations::make_range_looper(
|
||||
std::forward<Callable>(callable), begin);
|
||||
return detail::operations::loop(std::move(looper), end);
|
||||
}
|
||||
/// \}
|
||||
} // namespace cti
|
||||
|
||||
|
||||
@ -56,6 +56,8 @@ set(TEST_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-connection-all.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-connection-any.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-connection-seq.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-operations-async.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-operations-loop.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-erasure.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-regression.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-transforms.cpp)
|
||||
|
||||
28
test/unit-test/multi/test-continuable-operations-async.cpp
Normal file
28
test/unit-test/multi/test-continuable-operations-async.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
|
||||
/*
|
||||
Copyright(c) 2015 - 2019 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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.
|
||||
**/
|
||||
|
||||
#include <test-continuable.hpp>
|
||||
|
||||
TYPED_TEST(single_dimension_tests, operations_async_) {
|
||||
|
||||
}
|
||||
67
test/unit-test/multi/test-continuable-operations-loop.cpp
Normal file
67
test/unit-test/multi/test-continuable-operations-loop.cpp
Normal file
@ -0,0 +1,67 @@
|
||||
|
||||
/*
|
||||
Copyright(c) 2015 - 2019 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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.
|
||||
**/
|
||||
|
||||
#include <test-continuable.hpp>
|
||||
|
||||
using namespace cti;
|
||||
|
||||
static int const CANARY = 39472;
|
||||
|
||||
TYPED_TEST(single_dimension_tests, operations_loop_completion) {
|
||||
ASSERT_ASYNC_COMPLETION(loop([] {
|
||||
//
|
||||
return make_ready_continuable(make_result());
|
||||
}));
|
||||
|
||||
ASSERT_ASYNC_RESULT(loop(
|
||||
[](auto&&... args) {
|
||||
//
|
||||
return make_ready_continuable(make_result(
|
||||
std::forward<decltype(args)>(args)...));
|
||||
},
|
||||
CANARY),
|
||||
CANARY);
|
||||
|
||||
ASSERT_ASYNC_RESULT(loop(
|
||||
[](auto&&... args) {
|
||||
//
|
||||
return make_ready_continuable(make_result(
|
||||
std::forward<decltype(args)>(args)...));
|
||||
},
|
||||
CANARY, 2, CANARY),
|
||||
CANARY, 2, CANARY);
|
||||
}
|
||||
|
||||
TYPED_TEST(single_dimension_tests, operations_loop_looping) {
|
||||
int i = 0;
|
||||
|
||||
ASSERT_ASYNC_COMPLETION(range_loop(
|
||||
[&](int current) {
|
||||
EXPECT_EQ(current, i);
|
||||
++i;
|
||||
return make_ready_continuable();
|
||||
},
|
||||
0, 10));
|
||||
|
||||
ASSERT_EQ(i, 10);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user