mirror of
https://github.com/Kitware/CMake.git
synced 2026-01-13 09:49:42 -06:00
tests: Added tests to verify UV RAII semantics/constructs
This commit is contained in:
@@ -6,12 +6,16 @@ include_directories(
|
||||
|
||||
set(CMakeServerLib_TESTS
|
||||
testServerBuffering
|
||||
testUVRAII
|
||||
)
|
||||
|
||||
create_test_sourcelist(CMakeLib_TEST_SRCS CMakeServerLibTests.cxx ${CMakeServerLib_TESTS})
|
||||
add_executable(CMakeServerLibTests ${CMakeLib_TEST_SRCS})
|
||||
target_link_libraries(CMakeServerLibTests CMakeLib CMakeServerLib)
|
||||
|
||||
SET_PROPERTY(TARGET CMakeServerLibTests PROPERTY C_CLANG_TIDY "")
|
||||
SET_PROPERTY(TARGET CMakeServerLibTests PROPERTY CXX_CLANG_TIDY "")
|
||||
|
||||
foreach(test ${CMakeServerLib_TESTS})
|
||||
add_test(CMakeServerLib.${test} CMakeServerLibTests ${test} ${${test}_ARGS})
|
||||
endforeach()
|
||||
|
||||
179
Tests/CMakeServerLib/testUVRAII.cxx
Normal file
179
Tests/CMakeServerLib/testUVRAII.cxx
Normal file
@@ -0,0 +1,179 @@
|
||||
#include "cmUVHandlePtr.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
|
||||
#include "cm_uv.h"
|
||||
|
||||
static void signal_reset_fn(uv_async_t* handle)
|
||||
{
|
||||
auto ptr = static_cast<cm::uv_async_ptr*>(handle->data);
|
||||
ptr->reset();
|
||||
}
|
||||
|
||||
// A common pattern is to use an async signal to shutdown the server.
|
||||
static bool testAsyncShutdown()
|
||||
{
|
||||
uv_loop_t Loop;
|
||||
auto err = uv_loop_init(&Loop);
|
||||
if (err != 0) {
|
||||
std::cerr << "Could not init loop" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
cm::uv_async_ptr signal;
|
||||
signal.init(Loop, &signal_reset_fn, &signal);
|
||||
|
||||
std::thread([&] {
|
||||
std::this_thread::sleep_for(std::chrono::seconds(2));
|
||||
signal.send();
|
||||
}).detach();
|
||||
|
||||
if (uv_run(&Loop, UV_RUN_DEFAULT) != 0) {
|
||||
std::cerr << "Unclean exit state in testAsyncDtor" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (signal.get()) {
|
||||
std::cerr << "Loop exited with signal not being cleaned up" << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uv_loop_close(&Loop);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void signal_fn(uv_async_t*)
|
||||
{
|
||||
}
|
||||
|
||||
// Async dtor is sort of a pain; since it locks a mutex we must be sure its
|
||||
// dtor always calls reset otherwise the mutex is deleted then locked.
|
||||
static bool testAsyncDtor()
|
||||
{
|
||||
uv_loop_t Loop;
|
||||
auto err = uv_loop_init(&Loop);
|
||||
if (err != 0) {
|
||||
std::cerr << "Could not init loop" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
cm::uv_async_ptr signal;
|
||||
signal.init(Loop, signal_fn);
|
||||
}
|
||||
|
||||
if (uv_run(&Loop, UV_RUN_DEFAULT) != 0) {
|
||||
std::cerr << "Unclean exit state in testAsyncDtor" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
uv_loop_close(&Loop);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Async needs a relatively stateful deleter; make sure that is properly
|
||||
// accounted for and doesn't try to hold on to invalid state when it is
|
||||
// moved
|
||||
static bool testAsyncMove()
|
||||
{
|
||||
uv_loop_t Loop;
|
||||
auto err = uv_loop_init(&Loop);
|
||||
if (err != 0) {
|
||||
std::cerr << "Could not init loop" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
cm::uv_async_ptr signal;
|
||||
{
|
||||
cm::uv_async_ptr signalTmp;
|
||||
signalTmp.init(Loop, signal_fn);
|
||||
signal = std::move(signalTmp);
|
||||
}
|
||||
}
|
||||
|
||||
if (uv_run(&Loop, UV_RUN_DEFAULT) != 0) {
|
||||
std::cerr << "Unclean exit state in testAsyncDtor" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
uv_loop_close(&Loop);
|
||||
return true;
|
||||
}
|
||||
|
||||
// When a type is castable to another uv type (pipe -> stream) here,
|
||||
// and the deleter is convertible as well, we should allow moves from
|
||||
// one type to the other.
|
||||
static bool testCrossAssignment()
|
||||
{
|
||||
uv_loop_t Loop;
|
||||
auto err = uv_loop_init(&Loop);
|
||||
if (err != 0) {
|
||||
std::cerr << "Could not init loop" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
cm::uv_pipe_ptr pipe;
|
||||
pipe.init(Loop, 0);
|
||||
|
||||
cm::uv_stream_ptr stream = std::move(pipe);
|
||||
if (pipe.get()) {
|
||||
std::cerr << "Move should be sure to invalidate the previous ptr"
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
cm::uv_handle_ptr handle = std::move(stream);
|
||||
if (stream.get()) {
|
||||
std::cerr << "Move should be sure to invalidate the previous ptr"
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (uv_run(&Loop, UV_RUN_DEFAULT) != 0) {
|
||||
std::cerr << "Unclean exit state in testCrossAssignment" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
uv_loop_close(&Loop);
|
||||
return true;
|
||||
}
|
||||
|
||||
// This test can't fail at run time; but this makes sure we have all our move
|
||||
// ctors created correctly.
|
||||
static bool testAllMoves()
|
||||
{
|
||||
using namespace cm;
|
||||
struct allTypes
|
||||
{
|
||||
uv_stream_ptr _7;
|
||||
uv_tty_ptr _9;
|
||||
uv_pipe_ptr _12;
|
||||
uv_async_ptr _13;
|
||||
uv_signal_ptr _14;
|
||||
uv_handle_ptr _15;
|
||||
};
|
||||
|
||||
allTypes a;
|
||||
allTypes b(std::move(a));
|
||||
allTypes c = std::move(b);
|
||||
return true;
|
||||
};
|
||||
|
||||
int testUVRAII(int, char** const)
|
||||
{
|
||||
if ((testAsyncShutdown() &&
|
||||
testAsyncDtor() & testAsyncMove() & testCrossAssignment() &
|
||||
testAllMoves()) == 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user