First
This commit is contained in:
@@ -0,0 +1,248 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Lewis Baker
|
||||
// Licenced under MIT license. See LICENSE.txt for details.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <cppcoro/shared_task.hpp>
|
||||
#include <cppcoro/task.hpp>
|
||||
#include <cppcoro/sync_wait.hpp>
|
||||
#include <cppcoro/when_all_ready.hpp>
|
||||
#include <cppcoro/single_consumer_event.hpp>
|
||||
#include <cppcoro/fmap.hpp>
|
||||
|
||||
#include "counted.hpp"
|
||||
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
#include "doctest/cppcoro_doctest.h"
|
||||
|
||||
TEST_SUITE_BEGIN("shared_task");
|
||||
|
||||
TEST_CASE("awaiting default-constructed task throws broken_promise")
|
||||
{
|
||||
cppcoro::sync_wait([]() -> cppcoro::task<>
|
||||
{
|
||||
CHECK_THROWS_AS(co_await cppcoro::shared_task<>{}, const cppcoro::broken_promise&);
|
||||
}());
|
||||
}
|
||||
|
||||
TEST_CASE("coroutine doesn't start executing until awaited")
|
||||
{
|
||||
bool startedExecuting = false;
|
||||
auto f = [&]() -> cppcoro::shared_task<>
|
||||
{
|
||||
startedExecuting = true;
|
||||
co_return;
|
||||
};
|
||||
|
||||
auto t = f();
|
||||
|
||||
CHECK(!t.is_ready());
|
||||
CHECK(!startedExecuting);
|
||||
|
||||
cppcoro::sync_wait([](cppcoro::shared_task<> t) -> cppcoro::task<>
|
||||
{
|
||||
co_await t;
|
||||
}(t));
|
||||
|
||||
CHECK(t.is_ready());
|
||||
CHECK(startedExecuting);
|
||||
}
|
||||
|
||||
TEST_CASE("result is destroyed when last reference is destroyed")
|
||||
{
|
||||
counted::reset_counts();
|
||||
|
||||
{
|
||||
auto t = []() -> cppcoro::shared_task<counted>
|
||||
{
|
||||
co_return counted{};
|
||||
}();
|
||||
|
||||
CHECK(counted::active_count() == 0);
|
||||
|
||||
cppcoro::sync_wait(t);
|
||||
|
||||
CHECK(counted::active_count() == 1);
|
||||
}
|
||||
|
||||
CHECK(counted::active_count() == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("multiple awaiters")
|
||||
{
|
||||
cppcoro::single_consumer_event event;
|
||||
bool startedExecution = false;
|
||||
auto produce = [&]() -> cppcoro::shared_task<int>
|
||||
{
|
||||
startedExecution = true;
|
||||
co_await event;
|
||||
co_return 1;
|
||||
};
|
||||
|
||||
auto consume = [](cppcoro::shared_task<int> t) -> cppcoro::task<>
|
||||
{
|
||||
int result = co_await t;
|
||||
CHECK(result == 1);
|
||||
};
|
||||
|
||||
auto sharedTask = produce();
|
||||
|
||||
cppcoro::sync_wait(cppcoro::when_all_ready(
|
||||
consume(sharedTask),
|
||||
consume(sharedTask),
|
||||
consume(sharedTask),
|
||||
[&]() -> cppcoro::task<>
|
||||
{
|
||||
event.set();
|
||||
CHECK(sharedTask.is_ready());
|
||||
co_return;
|
||||
}()));
|
||||
|
||||
CHECK(sharedTask.is_ready());
|
||||
}
|
||||
|
||||
TEST_CASE("waiting on shared_task in loop doesn't cause stack-overflow")
|
||||
{
|
||||
// This test checks that awaiting a shared_task that completes
|
||||
// synchronously doesn't recursively resume the awaiter inside the
|
||||
// call to start executing the task. If it were to do this then we'd
|
||||
// expect that this test would result in failure due to stack-overflow.
|
||||
|
||||
auto completesSynchronously = []() -> cppcoro::shared_task<int>
|
||||
{
|
||||
co_return 1;
|
||||
};
|
||||
|
||||
cppcoro::sync_wait([&]() -> cppcoro::task<>
|
||||
{
|
||||
int result = 0;
|
||||
for (int i = 0; i < 1'000'000; ++i)
|
||||
{
|
||||
result += co_await completesSynchronously();
|
||||
}
|
||||
CHECK(result == 1'000'000);
|
||||
}());
|
||||
}
|
||||
|
||||
TEST_CASE("make_shared_task")
|
||||
{
|
||||
bool startedExecution = false;
|
||||
|
||||
auto f = [&]() -> cppcoro::task<std::string>
|
||||
{
|
||||
startedExecution = false;
|
||||
co_return "test";
|
||||
};
|
||||
|
||||
auto t = f();
|
||||
|
||||
cppcoro::shared_task<std::string> sharedT =
|
||||
cppcoro::make_shared_task(std::move(t));
|
||||
|
||||
CHECK(!sharedT.is_ready());
|
||||
CHECK(!startedExecution);
|
||||
|
||||
auto consume = [](cppcoro::shared_task<std::string> t) -> cppcoro::task<>
|
||||
{
|
||||
auto x = co_await std::move(t);
|
||||
CHECK(x == "test");
|
||||
};
|
||||
|
||||
cppcoro::sync_wait(cppcoro::when_all_ready(
|
||||
consume(sharedT),
|
||||
consume(sharedT)));
|
||||
}
|
||||
|
||||
TEST_CASE("make_shared_task of void"
|
||||
* doctest::description{ "Tests that workaround for 'co_return <void-expr>' bug is operational if required" })
|
||||
{
|
||||
bool startedExecution = false;
|
||||
|
||||
auto f = [&]() -> cppcoro::task<>
|
||||
{
|
||||
startedExecution = true;
|
||||
co_return;
|
||||
};
|
||||
|
||||
auto t = f();
|
||||
|
||||
cppcoro::shared_task<> sharedT = cppcoro::make_shared_task(std::move(t));
|
||||
|
||||
CHECK(!sharedT.is_ready());
|
||||
CHECK(!startedExecution);
|
||||
|
||||
auto consume = [](cppcoro::shared_task<> t) -> cppcoro::task<>
|
||||
{
|
||||
co_await t;
|
||||
};
|
||||
|
||||
auto c1 = consume(sharedT);
|
||||
cppcoro::sync_wait(c1);
|
||||
|
||||
CHECK(startedExecution);
|
||||
|
||||
auto c2 = consume(sharedT);
|
||||
cppcoro::sync_wait(c2);
|
||||
|
||||
CHECK(c1.is_ready());
|
||||
CHECK(c2.is_ready());
|
||||
}
|
||||
|
||||
TEST_CASE("shared_task<void> fmap operator")
|
||||
{
|
||||
cppcoro::single_consumer_event event;
|
||||
int value = 0;
|
||||
|
||||
auto setNumber = [&]() -> cppcoro::shared_task<>
|
||||
{
|
||||
co_await event;
|
||||
value = 123;
|
||||
};
|
||||
|
||||
cppcoro::sync_wait(cppcoro::when_all_ready(
|
||||
[&]() -> cppcoro::task<>
|
||||
{
|
||||
auto numericStringTask =
|
||||
setNumber()
|
||||
| cppcoro::fmap([&]() { return std::to_string(value); });
|
||||
|
||||
CHECK(co_await numericStringTask == "123");
|
||||
}(),
|
||||
[&]() -> cppcoro::task<>
|
||||
{
|
||||
CHECK(value == 0);
|
||||
event.set();
|
||||
CHECK(value == 123);
|
||||
co_return;
|
||||
}()));
|
||||
}
|
||||
|
||||
TEST_CASE("shared_task<T> fmap operator")
|
||||
{
|
||||
cppcoro::single_consumer_event event;
|
||||
|
||||
auto getNumber = [&]() -> cppcoro::shared_task<int>
|
||||
{
|
||||
co_await event;
|
||||
co_return 123;
|
||||
};
|
||||
|
||||
cppcoro::sync_wait(cppcoro::when_all_ready(
|
||||
[&]() -> cppcoro::task<>
|
||||
{
|
||||
auto numericStringTask =
|
||||
getNumber()
|
||||
| cppcoro::fmap([](int x) { return std::to_string(x); });
|
||||
|
||||
CHECK(co_await numericStringTask == "123");
|
||||
}(),
|
||||
[&]() -> cppcoro::task<>
|
||||
{
|
||||
event.set();
|
||||
co_return;
|
||||
}()));
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
Reference in New Issue
Block a user