diff options
Diffstat (limited to 'Tests/CMakeLib/testUVStreambuf.cxx')
-rw-r--r-- | Tests/CMakeLib/testUVStreambuf.cxx | 457 |
1 files changed, 457 insertions, 0 deletions
diff --git a/Tests/CMakeLib/testUVStreambuf.cxx b/Tests/CMakeLib/testUVStreambuf.cxx new file mode 100644 index 000000000..39655f372 --- /dev/null +++ b/Tests/CMakeLib/testUVStreambuf.cxx @@ -0,0 +1,457 @@ +#include "cmUVStreambuf.h" + +#include "cmGetPipes.h" +#include "cmUVHandlePtr.h" + +#include "cm_uv.h" + +#include <iostream> +#include <string> +#include <vector> + +#include <cstring> + +#include <stdint.h> + +#define TEST_STR_LINE_1 "This string must be exactly 128 characters long so" +#define TEST_STR_LINE_2 "that we can test CMake's std::streambuf integration" +#define TEST_STR_LINE_3 "with libuv's uv_stream_t." +#define TEST_STR TEST_STR_LINE_1 "\n" TEST_STR_LINE_2 "\n" TEST_STR_LINE_3 + +bool writeDataToStreamPipe(uv_loop_t& loop, cm::uv_pipe_ptr& inputPipe, + char* outputData, unsigned int outputDataLength, + const char* /* unused */) +{ + int err; + + // Create the pipe + int pipeHandles[2]; + if (cmGetPipes(pipeHandles) < 0) { + std::cout << "Could not open pipe" << std::endl; + return false; + } + + cm::uv_pipe_ptr outputPipe; + inputPipe.init(loop, 0); + outputPipe.init(loop, 0); + uv_pipe_open(inputPipe, pipeHandles[0]); + uv_pipe_open(outputPipe, pipeHandles[1]); + + // Write data for reading + uv_write_t writeReq; + struct WriteCallbackData + { + bool Finished = false; + int Status; + } writeData; + writeReq.data = &writeData; + uv_buf_t outputBuf; + outputBuf.base = outputData; + outputBuf.len = outputDataLength; + if ((err = uv_write(&writeReq, outputPipe, &outputBuf, 1, + [](uv_write_t* req, int status) { + auto data = static_cast<WriteCallbackData*>(req->data); + data->Finished = true; + data->Status = status; + })) < 0) { + std::cout << "Could not write to pipe: " << uv_strerror(err) << std::endl; + return false; + } + while (!writeData.Finished) { + uv_run(&loop, UV_RUN_ONCE); + } + if (writeData.Status < 0) { + std::cout << "Status is " << uv_strerror(writeData.Status) + << ", should be 0" << std::endl; + return false; + } + + return true; +} + +bool writeDataToStreamProcess(uv_loop_t& loop, cm::uv_pipe_ptr& inputPipe, + char* outputData, unsigned int /* unused */, + const char* cmakeCommand) +{ + int err; + + inputPipe.init(loop, 0); + std::vector<std::string> arguments = { cmakeCommand, "-E", "echo_append", + outputData }; + std::vector<const char*> processArgs; + for (auto const& arg : arguments) { + processArgs.push_back(arg.c_str()); + } + processArgs.push_back(nullptr); + std::vector<uv_stdio_container_t> stdio(3); + stdio[0].flags = UV_IGNORE; + stdio[0].data.stream = nullptr; + stdio[1].flags = + static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE); + stdio[1].data.stream = inputPipe; + stdio[2].flags = UV_IGNORE; + stdio[2].data.stream = nullptr; + + struct ProcessExitData + { + bool Finished = false; + int64_t ExitStatus; + int TermSignal; + } exitData; + cm::uv_process_ptr process; + auto options = uv_process_options_t(); + options.file = cmakeCommand; + options.args = const_cast<char**>(processArgs.data()); + options.flags = UV_PROCESS_WINDOWS_HIDE; + options.stdio = stdio.data(); + options.stdio_count = static_cast<int>(stdio.size()); + options.exit_cb = [](uv_process_t* handle, int64_t exitStatus, + int termSignal) { + auto data = static_cast<ProcessExitData*>(handle->data); + data->Finished = true; + data->ExitStatus = exitStatus; + data->TermSignal = termSignal; + }; + if ((err = process.spawn(loop, options, &exitData)) < 0) { + std::cout << "Could not spawn process: " << uv_strerror(err) << std::endl; + return false; + } + while (!exitData.Finished) { + uv_run(&loop, UV_RUN_ONCE); + } + if (exitData.ExitStatus != 0) { + std::cout << "Process exit status is " << exitData.ExitStatus + << ", should be 0" << std::endl; + return false; + } + if (exitData.TermSignal != 0) { + std::cout << "Process term signal is " << exitData.TermSignal + << ", should be 0" << std::endl; + return false; + } + + return true; +} + +bool testUVStreambufRead( + bool (*cb)(uv_loop_t& loop, cm::uv_pipe_ptr& inputPipe, char* outputData, + unsigned int outputDataLength, const char* cmakeCommand), + const char* cmakeCommand) +{ + char outputData[] = TEST_STR; + bool success = false; + cm::uv_loop_ptr loop; + loop.init(); + cm::uv_pipe_ptr inputPipe; + std::vector<char> inputData(128); + std::streamsize readLen; + std::string line; + cm::uv_timer_ptr timer; + + // Create the streambuf + cmUVStreambuf inputBuf(64); + std::istream inputStream(&inputBuf); + if (inputBuf.is_open()) { + std::cout << "is_open() is true, should be false" << std::endl; + goto end; + } + if ((readLen = inputBuf.in_avail()) != -1) { + std::cout << "in_avail() returned " << readLen << ", should be -1" + << std::endl; + goto end; + } + if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 0) { + std::cout << "sgetn() returned " << readLen << ", should be 0" + << std::endl; + goto end; + } + + // Perform first read test - read all the data + if (!cb(*loop, inputPipe, outputData, 128, cmakeCommand)) { + goto end; + } + inputBuf.open(inputPipe); + if (!inputBuf.is_open()) { + std::cout << "is_open() is false, should be true" << std::endl; + goto end; + } + if ((readLen = inputBuf.in_avail()) != 0) { + std::cout << "in_avail() returned " << readLen << ", should be 0" + << std::endl; + goto end; + } + if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 128) { + std::cout << "sgetn() returned " << readLen << ", should be 128" + << std::endl; + goto end; + } + if ((readLen = inputBuf.in_avail()) != 0) { + std::cout << "in_avail() returned " << readLen << ", should be 0" + << std::endl; + goto end; + } + if (std::memcmp(inputData.data(), outputData, 128)) { + std::cout << "Read data does not match write data" << std::endl; + goto end; + } + if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 0) { + std::cout << "sgetn() returned " << readLen << ", should be 0" + << std::endl; + goto end; + } + if ((readLen = inputBuf.in_avail()) != -1) { + std::cout << "in_avail() returned " << readLen << ", should be -1" + << std::endl; + goto end; + } + inputData.assign(128, char{}); + inputBuf.close(); + if (inputBuf.is_open()) { + std::cout << "is_open() is true, should be false" << std::endl; + goto end; + } + if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 0) { + std::cout << "sgetn() returned " << readLen << ", should be 0" + << std::endl; + goto end; + } + if ((readLen = inputBuf.in_avail()) != -1) { + std::cout << "in_avail() returned " << readLen << ", should be -1" + << std::endl; + goto end; + } + + // Perform second read test - read some data and then close + if (!cb(*loop, inputPipe, outputData, 128, cmakeCommand)) { + goto end; + } + inputBuf.open(inputPipe); + if (!inputBuf.is_open()) { + std::cout << "is_open() is false, should be true" << std::endl; + goto end; + } + if ((readLen = inputBuf.in_avail()) != 0) { + std::cout << "in_avail() returned " << readLen << ", should be 0" + << std::endl; + goto end; + } + if ((readLen = inputBuf.sgetn(inputData.data(), 64)) != 64) { + std::cout << "sgetn() returned " << readLen << ", should be 64" + << std::endl; + goto end; + } + if (std::memcmp(inputData.data(), outputData, 64)) { + std::cout << "Read data does not match write data" << std::endl; + goto end; + } + if ((readLen = inputBuf.in_avail()) != 8) { + std::cout << "in_avail() returned " << readLen << ", should be 8" + << std::endl; + goto end; + } + inputData.assign(128, char{}); + inputBuf.close(); + if (inputBuf.is_open()) { + std::cout << "is_open() is true, should be false" << std::endl; + goto end; + } + if ((readLen = inputBuf.in_avail()) != -1) { + std::cout << "in_avail() returned " << readLen << ", should be -1" + << std::endl; + goto end; + } + if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 0) { + std::cout << "sgetn() returned " << readLen << ", should be 0" + << std::endl; + goto end; + } + + // Perform third read test - read line by line + if (!cb(*loop, inputPipe, outputData, 128, cmakeCommand)) { + goto end; + } + inputBuf.open(inputPipe); + if (!inputBuf.is_open()) { + std::cout << "is_open() is false, should be true" << std::endl; + goto end; + } + if ((readLen = inputBuf.in_avail()) != 0) { + std::cout << "in_avail() returned " << readLen << ", should be 0" + << std::endl; + goto end; + } + + if (!std::getline(inputStream, line)) { + std::cout << "getline returned false, should be true" << std::endl; + goto end; + } + if (line != TEST_STR_LINE_1) { + std::cout << "Line 1 is \"" << line + << "\", should be \"" TEST_STR_LINE_1 "\"" << std::endl; + goto end; + } + + if (!std::getline(inputStream, line)) { + std::cout << "getline returned false, should be true" << std::endl; + goto end; + } + if (line != TEST_STR_LINE_2) { + std::cout << "Line 2 is \"" << line + << "\", should be \"" TEST_STR_LINE_2 "\"" << std::endl; + goto end; + } + + if (!std::getline(inputStream, line)) { + std::cout << "getline returned false, should be true" << std::endl; + goto end; + } + if (line != TEST_STR_LINE_3) { + std::cout << "Line 3 is \"" << line + << "\", should be \"" TEST_STR_LINE_3 "\"" << std::endl; + goto end; + } + + if (std::getline(inputStream, line)) { + std::cout << "getline returned true, should be false" << std::endl; + goto end; + } + + inputBuf.close(); + if (inputBuf.is_open()) { + std::cout << "is_open() is true, should be false" << std::endl; + goto end; + } + if ((readLen = inputBuf.in_avail()) != -1) { + std::cout << "in_avail() returned " << readLen << ", should be -1" + << std::endl; + goto end; + } + if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 0) { + std::cout << "sgetn() returned " << readLen << ", should be 0" + << std::endl; + goto end; + } + + // Perform fourth read test - run the event loop outside of underflow() + if (!cb(*loop, inputPipe, outputData, 128, cmakeCommand)) { + goto end; + } + inputBuf.open(inputPipe); + if (!inputBuf.is_open()) { + std::cout << "is_open() is false, should be true" << std::endl; + goto end; + } + if ((readLen = inputBuf.in_avail()) != 0) { + std::cout << "in_avail() returned " << readLen << ", should be 0" + << std::endl; + goto end; + } + uv_run(loop, UV_RUN_DEFAULT); + if ((readLen = inputBuf.in_avail()) != 72) { + std::cout << "in_avail() returned " << readLen << ", should be 72" + << std::endl; + goto end; + } + if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 128) { + std::cout << "sgetn() returned " << readLen << ", should be 128" + << std::endl; + goto end; + } + if ((readLen = inputBuf.in_avail()) != 0) { + std::cout << "in_avail() returned " << readLen << ", should be 0" + << std::endl; + goto end; + } + if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 0) { + std::cout << "sgetn() returned " << readLen << ", should be 128" + << std::endl; + goto end; + } + if ((readLen = inputBuf.in_avail()) != -1) { + std::cout << "in_avail() returned " << readLen << ", should be -1" + << std::endl; + goto end; + } + + inputBuf.close(); + if (inputBuf.is_open()) { + std::cout << "is_open() is true, should be false" << std::endl; + goto end; + } + if ((readLen = inputBuf.in_avail()) != -1) { + std::cout << "in_avail() returned " << readLen << ", should be -1" + << std::endl; + goto end; + } + if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 0) { + std::cout << "sgetn() returned " << readLen << ", should be 0" + << std::endl; + goto end; + } + + // Perform fifth read test - close the streambuf in the middle of a read + timer.init(*loop, &inputBuf); + if (!cb(*loop, inputPipe, outputData, 128, cmakeCommand)) { + goto end; + } + inputBuf.open(inputPipe); + if (!inputBuf.is_open()) { + std::cout << "is_open() is false, should be true" << std::endl; + goto end; + } + if ((readLen = inputBuf.in_avail()) != 0) { + std::cout << "in_avail() returned " << readLen << ", should be 0" + << std::endl; + goto end; + } + uv_timer_start(timer, + [](uv_timer_t* handle) { + auto buf = static_cast<cmUVStreambuf*>(handle->data); + buf->close(); + }, + 0, 0); + if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 0) { + std::cout << "sgetn() returned " << readLen << ", should be 0" + << std::endl; + goto end; + } + if (inputBuf.is_open()) { + std::cout << "is_open() is true, should be false" << std::endl; + goto end; + } + if ((readLen = inputBuf.in_avail()) != -1) { + std::cout << "in_avail() returned " << readLen << ", should be -1" + << std::endl; + goto end; + } + if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 0) { + std::cout << "sgetn() returned " << readLen << ", should be 0" + << std::endl; + goto end; + } + + success = true; + +end: + return success; +} + +int testUVStreambuf(int argc, char** const argv) +{ + if (argc < 2) { + std::cout << "Invalid arguments.\n"; + return -1; + } + + if (!testUVStreambufRead(writeDataToStreamPipe, argv[1])) { + std::cout << "While executing testUVStreambufRead() with pipe.\n"; + return -1; + } + + if (!testUVStreambufRead(writeDataToStreamProcess, argv[1])) { + std::cout << "While executing testUVStreambufRead() with process.\n"; + return -1; + } + + return 0; +} |