Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a36dcdb

Browse files
committed
Add some more async_stream tests.
- Test for terminating consumption of a stream before the end. - Test for composing streams using take(n, subscribable)
1 parent ce6f3ff commit a36dcdb

File tree

3 files changed

+100
-0
lines changed

3 files changed

+100
-0
lines changed

include/cppcoro/async_stream.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,8 @@ namespace cppcoro
320320

321321
public:
322322

323+
using value_type = std::remove_reference_t<T>;
324+
323325
async_stream(handle_t coroutine) noexcept
324326
: m_coroutine(coroutine)
325327
{}

include/cppcoro/consume.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#ifndef CPPCORO_CONSUME_HPP_INCLUDED
66
#define CPPCORO_CONSUME_HPP_INCLUDED
77

8+
#include <functional>
9+
810
namespace cppcoro
911
{
1012
template<typename SUBSCRIBABLE, typename CONSUME_FUNC>

test/async_stream_tests.cpp

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,100 @@ TEST_CASE("consume async_stream")
4343
CHECK(result == 3);
4444
}
4545

46+
TEST_CASE("producer exiting early on destruction of stream")
47+
{
48+
int lastProduced = -1;
49+
bool ranFinalisation = false;
50+
51+
auto subscribable = make_subscribable(
52+
[&]() -> async_stream_subscription<int>
53+
{
54+
for (int i = 0; i < 5; ++i)
55+
{
56+
lastProduced = i;
57+
bool produceMore = co_yield i;
58+
if (!produceMore) break;
59+
}
60+
61+
ranFinalisation = true;
62+
});
63+
64+
sync_wait(consume(subscribable, [](async_stream<int> stream) -> task<>
65+
{
66+
// TRICKY: Need to move parameter to local var here to ensure it is destructed when the
67+
// coroutine runs to completion. Normally, the destructor of parameters won't run until
68+
// the coroutine is destroyed. However, the coroutine won't be destroyed until the
69+
// entire consume operation completes, which includes waiting until the producer coroutine
70+
// runs to completion. However, the producer coroutine isn't going to run to completion
71+
// unless we either consume it completely or detach from the stream, causing a deadlock.
72+
auto localStream = std::move(stream);
73+
for co_await(int value : localStream)
74+
{
75+
// Don't consume any more values once we get to '3'.
76+
if (value == 3) break;
77+
}
78+
}));
79+
80+
CHECK(lastProduced == 3);
81+
CHECK(ranFinalisation);
82+
}
83+
84+
template<typename COUNT, typename SUBSCRIBABLE>
85+
auto take(COUNT n, SUBSCRIBABLE&& s)
86+
{
87+
return make_subscribable(
88+
[n, s = std::forward<SUBSCRIBABLE>(s)]
89+
{
90+
auto[sourceStream, sourceTask] = s.subscribe();
91+
92+
using value_type = typename std::remove_reference_t<decltype(sourceStream)>::value_type;
93+
94+
auto[outputStream, outputTask] = [](COUNT n, auto stream) -> async_stream_subscription<value_type>
95+
{
96+
auto localStream = std::move(stream);
97+
if (n > 0)
98+
{
99+
for co_await(auto&& value : localStream)
100+
{
101+
bool produceMore = co_yield value;
102+
if (!produceMore) break;
103+
if (--n == 0) break;
104+
}
105+
}
106+
}(n, std::move(sourceStream));
107+
108+
return std::make_tuple(
109+
std::move(outputStream),
110+
when_all(std::move(sourceTask), std::move(outputTask)) | fmap([](auto) {}));
111+
});
112+
}
113+
114+
TEST_CASE("take(5)")
115+
{
116+
auto subscribable = take(5, make_subscribable([]() -> async_stream_subscription<int>
117+
{
118+
for (int i = 0; i < 10; ++i)
119+
{
120+
bool produceMore = co_yield i;
121+
if (!produceMore) break;
122+
}
123+
}));
124+
125+
auto values = sync_wait(consume(subscribable, [](async_stream<int> stream) -> task<std::vector<int>>
126+
{
127+
auto localStream = std::move(stream);
128+
129+
std::vector<int> values;
130+
for co_await(int value : localStream)
131+
{
132+
values.push_back(value);
133+
}
134+
return std::move(values);
135+
}));
136+
137+
CHECK(values.size() == 5);
138+
CHECK(values[0] == 0);
139+
CHECK(values[4] == 4);
140+
}
141+
46142
TEST_SUITE_END();

0 commit comments

Comments
 (0)