summaryrefslogtreecommitdiffstats
path: root/Tests/CMakeServerLib
diff options
context:
space:
mode:
authorJustin Berger <j.david.berger@gmail.com>2017-11-10 03:52:32 (GMT)
committerBrad King <brad.king@kitware.com>2017-11-29 21:36:31 (GMT)
commitf43b9219c738944fea33043b1985696c862c84ac (patch)
tree706681eddd9764a47a00ead69fec27c22f61b6f9 /Tests/CMakeServerLib
parenta3abb85c6ff5aebe2220ae612512a434b491eedd (diff)
downloadCMake-f43b9219c738944fea33043b1985696c862c84ac.zip
CMake-f43b9219c738944fea33043b1985696c862c84ac.tar.gz
CMake-f43b9219c738944fea33043b1985696c862c84ac.tar.bz2
tests: Added tests to verify UV RAII semantics/constructs
Diffstat (limited to 'Tests/CMakeServerLib')
-rw-r--r--Tests/CMakeServerLib/CMakeLists.txt4
-rw-r--r--Tests/CMakeServerLib/testUVRAII.cxx179
2 files changed, 183 insertions, 0 deletions
diff --git a/Tests/CMakeServerLib/CMakeLists.txt b/Tests/CMakeServerLib/CMakeLists.txt
index f5351fd..f1ca2a4 100644
--- a/Tests/CMakeServerLib/CMakeLists.txt
+++ b/Tests/CMakeServerLib/CMakeLists.txt
@@ -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()
diff --git a/Tests/CMakeServerLib/testUVRAII.cxx b/Tests/CMakeServerLib/testUVRAII.cxx
new file mode 100644
index 0000000..7ecef39
--- /dev/null
+++ b/Tests/CMakeServerLib/testUVRAII.cxx
@@ -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;
+}