Files
revng-revng/tests/unit/RecursiveCoroutine2.cpp
Alessandro Di Federico 5820908675 Remove and ban \file
2025-12-16 17:41:55 +01:00

123 lines
2.8 KiB
C++

/// Tests `RecursiveCoroutine`
//
// This file is distributed under the MIT License. See LICENSE.md for details.
//
#define BOOST_TEST_MODULE RecursiveCoroutine2
bool init_unit_test();
#include "boost/test/unit_test.hpp"
#include "revng/ADT/RecursiveCoroutine.h"
namespace {
class InstanceCounter {
int *Counter;
public:
InstanceCounter(int &Counter) : Counter(&Counter) { ++*this->Counter; }
InstanceCounter(const InstanceCounter &Other) : Counter(Other.Counter) {
++*this->Counter;
}
InstanceCounter &operator=(const InstanceCounter &Other) {
--*this->Counter;
this->Counter = Other.Counter;
++*this->Counter;
return *this;
}
~InstanceCounter() { --*this->Counter; }
};
class TestMutex {
bool IsLocked = false;
public:
void lock() {
revng_check(not IsLocked);
IsLocked = true;
}
void unlock() {
revng_check(IsLocked);
IsLocked = false;
}
};
} // namespace
// Test that the coroutine is destroyed before its result can be accessed in a
// non-coroutine context.
BOOST_AUTO_TEST_CASE(RecursiveCoroutineEvaluationOrder1) {
TestMutex Mutex;
int GuardedValue = 1;
auto F = [&]() -> RecursiveCoroutine<int> {
std::lock_guard Lock(Mutex);
rc_return GuardedValue++;
};
auto G = [&](int Value) -> std::pair<int, int> {
std::lock_guard Lock(Mutex);
return { Value, GuardedValue++ };
};
std::pair<int, int> P = G(F());
revng_check(P.first == 1);
revng_check(P.second == 2);
}
// Test that the coroutine is destroyed before its result can be accessed after
// being awaited.
BOOST_AUTO_TEST_CASE(RecursiveCoroutineEvaluationOrder2) {
TestMutex Mutex;
int GuardedValue = 1;
auto F = [&]() -> RecursiveCoroutine<int> {
std::lock_guard Lock(Mutex);
rc_return GuardedValue++;
};
auto G = [&](int Value) -> RecursiveCoroutine<std::pair<int, int>> {
std::lock_guard Lock(Mutex);
rc_return{ Value, GuardedValue++ };
};
auto H = [&]() -> RecursiveCoroutine<std::pair<int, int>> {
rc_return rc_recur G(rc_recur F());
};
std::pair<int, int> P = H();
revng_check(P.first == 1);
revng_check(P.second == 2);
}
// Test that no moved-from copy of the coroutine result exists when it is
// observed by a non-coroutine caller.
BOOST_AUTO_TEST_CASE(RecursiveCoroutineEvaluationOrder3) {
int Counter = 0;
auto F = [&]() -> RecursiveCoroutine<InstanceCounter> { rc_return Counter; };
auto G = [&](InstanceCounter) { revng_check(Counter == 1); };
G(F());
}
// Test that no moved-from copy of the coroutine result exists when it is
// observed after being awaited.
BOOST_AUTO_TEST_CASE(RecursiveCoroutineEvaluationOrder4) {
int Counter = 0;
auto F = [&]() -> RecursiveCoroutine<InstanceCounter> { rc_return Counter; };
auto G = [&](InstanceCounter) { revng_check(Counter == 1); };
auto H = [&]() -> RecursiveCoroutine<void> { G(rc_recur F()); };
H();
}