| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337 |
- #include "cmUVProcessChain.h"
- #include "cmGetPipes.h"
- #include "cmUVHandlePtr.h"
- #include "cmUVStreambuf.h"
- #include "cm_uv.h"
- #include <algorithm>
- #include <functional>
- #include <iostream>
- #include <memory>
- #include <sstream>
- #include <string>
- #include <vector>
- #include <csignal>
- #include "cm_memory.hxx"
- struct ExpectedStatus
- {
- bool Finished;
- bool MatchExitStatus;
- bool MatchTermSignal;
- cmUVProcessChain::Status Status;
- };
- static const std::vector<ExpectedStatus> status1 = {
- { false, false, false, { 0, 0 } },
- { false, false, false, { 0, 0 } },
- { false, false, false, { 0, 0 } },
- };
- static const std::vector<ExpectedStatus> status2 = {
- { true, true, true, { 0, 0 } },
- { false, false, false, { 0, 0 } },
- { false, false, false, { 0, 0 } },
- };
- static const std::vector<ExpectedStatus> status3 = {
- { true, true, true, { 0, 0 } },
- { true, true, true, { 1, 0 } },
- #ifdef _WIN32
- { true, true, true, { 2, 0 } },
- #else
- { true, false, true, { 0, SIGABRT } },
- #endif
- };
- bool operator==(const cmUVProcessChain::Status* actual,
- const ExpectedStatus& expected)
- {
- if (!expected.Finished) {
- return !actual;
- } else if (!actual) {
- return false;
- }
- if (expected.MatchExitStatus &&
- expected.Status.ExitStatus != actual->ExitStatus) {
- return false;
- }
- if (expected.MatchTermSignal &&
- expected.Status.TermSignal != actual->TermSignal) {
- return false;
- }
- return true;
- }
- bool resultsMatch(const std::vector<const cmUVProcessChain::Status*>& actual,
- const std::vector<ExpectedStatus>& expected)
- {
- return actual.size() == expected.size() &&
- std::equal(actual.begin(), actual.end(), expected.begin());
- }
- std::string getInput(std::istream& input)
- {
- char buffer[1024];
- std::ostringstream str;
- do {
- input.read(buffer, 1024);
- str.write(buffer, input.gcount());
- } while (input.gcount() > 0);
- return str.str();
- }
- template <typename T>
- std::function<std::ostream&(std::ostream&)> printExpected(bool match,
- const T& value)
- {
- return [match, value](std::ostream& stream) -> std::ostream& {
- if (match) {
- stream << value;
- } else {
- stream << "*";
- }
- return stream;
- };
- }
- std::ostream& operator<<(
- std::ostream& stream,
- const std::function<std::ostream&(std::ostream&)>& func)
- {
- return func(stream);
- }
- void printResults(const std::vector<const cmUVProcessChain::Status*>& actual,
- const std::vector<ExpectedStatus>& expected)
- {
- std::cout << "Expected: " << std::endl;
- for (auto const& e : expected) {
- if (e.Finished) {
- std::cout << " ExitStatus: "
- << printExpected(e.MatchExitStatus, e.Status.ExitStatus)
- << ", TermSignal: "
- << printExpected(e.MatchTermSignal, e.Status.TermSignal)
- << std::endl;
- } else {
- std::cout << " null" << std::endl;
- }
- }
- std::cout << "Actual:" << std::endl;
- for (auto const& a : actual) {
- if (a) {
- std::cout << " ExitStatus: " << a->ExitStatus
- << ", TermSignal: " << a->TermSignal << std::endl;
- } else {
- std::cout << " null" << std::endl;
- }
- }
- }
- bool checkExecution(cmUVProcessChainBuilder& builder,
- std::unique_ptr<cmUVProcessChain>& chain)
- {
- std::vector<const cmUVProcessChain::Status*> status;
- chain = cm::make_unique<cmUVProcessChain>(builder.Start());
- if (!chain->Valid()) {
- std::cout << "Valid() returned false, should be true" << std::endl;
- return false;
- }
- status = chain->GetStatus();
- if (!resultsMatch(status, status1)) {
- std::cout << "GetStatus() did not produce expected output" << std::endl;
- printResults(status, status1);
- return false;
- }
- if (chain->Wait(6000)) {
- std::cout << "Wait() returned true, should be false" << std::endl;
- return false;
- }
- status = chain->GetStatus();
- if (!resultsMatch(status, status2)) {
- std::cout << "GetStatus() did not produce expected output" << std::endl;
- printResults(status, status2);
- return false;
- }
- if (!chain->Wait()) {
- std::cout << "Wait() returned false, should be true" << std::endl;
- return false;
- }
- status = chain->GetStatus();
- if (!resultsMatch(status, status3)) {
- std::cout << "GetStatus() did not produce expected output" << std::endl;
- printResults(status, status3);
- return false;
- }
- return true;
- }
- bool checkOutput(std::istream& outputStream, std::istream& errorStream)
- {
- std::string output = getInput(outputStream);
- if (output != "HELO WRD!") {
- std::cout << "Output was \"" << output << "\", expected \"HELO WRD!\""
- << std::endl;
- return false;
- }
- std::string error = getInput(errorStream);
- if (error.length() != 3 || error.find('1') == std::string::npos ||
- error.find('2') == std::string::npos ||
- error.find('3') == std::string::npos) {
- std::cout << "Error was \"" << error << "\", expected \"123\""
- << std::endl;
- return false;
- }
- return true;
- }
- bool testUVProcessChainBuiltin(const char* helperCommand)
- {
- cmUVProcessChainBuilder builder;
- std::unique_ptr<cmUVProcessChain> chain;
- builder.AddCommand({ helperCommand, "echo" })
- .AddCommand({ helperCommand, "capitalize" })
- .AddCommand({ helperCommand, "dedup" })
- .SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
- .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR);
- if (!checkExecution(builder, chain)) {
- return false;
- }
- if (!chain->OutputStream()) {
- std::cout << "OutputStream() was null, expecting not null" << std::endl;
- return false;
- }
- if (!chain->ErrorStream()) {
- std::cout << "ErrorStream() was null, expecting not null" << std::endl;
- return false;
- }
- if (!checkOutput(*chain->OutputStream(), *chain->ErrorStream())) {
- return false;
- }
- return true;
- }
- bool testUVProcessChainExternal(const char* helperCommand)
- {
- cmUVProcessChainBuilder builder;
- std::unique_ptr<cmUVProcessChain> chain;
- int outputPipe[2], errorPipe[2];
- cm::uv_pipe_ptr outputInPipe, outputOutPipe, errorInPipe, errorOutPipe;
- if (cmGetPipes(outputPipe) < 0) {
- std::cout << "Error creating pipes" << std::endl;
- return false;
- }
- if (cmGetPipes(errorPipe) < 0) {
- std::cout << "Error creating pipes" << std::endl;
- return false;
- }
- builder.AddCommand({ helperCommand, "echo" })
- .AddCommand({ helperCommand, "capitalize" })
- .AddCommand({ helperCommand, "dedup" })
- .SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT, outputPipe[1])
- .SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR, errorPipe[1]);
- if (!checkExecution(builder, chain)) {
- return false;
- }
- if (chain->OutputStream()) {
- std::cout << "OutputStream() was not null, expecting null" << std::endl;
- return false;
- }
- if (chain->ErrorStream()) {
- std::cout << "ErrorStream() was not null, expecting null" << std::endl;
- return false;
- }
- outputOutPipe.init(chain->GetLoop(), 0);
- uv_pipe_open(outputOutPipe, outputPipe[1]);
- outputOutPipe.reset();
- errorOutPipe.init(chain->GetLoop(), 0);
- uv_pipe_open(errorOutPipe, errorPipe[1]);
- errorOutPipe.reset();
- outputInPipe.init(chain->GetLoop(), 0);
- uv_pipe_open(outputInPipe, outputPipe[0]);
- cmUVStreambuf outputBuf;
- outputBuf.open(outputInPipe);
- std::istream outputStream(&outputBuf);
- errorInPipe.init(chain->GetLoop(), 0);
- uv_pipe_open(errorInPipe, errorPipe[0]);
- cmUVStreambuf errorBuf;
- errorBuf.open(errorInPipe);
- std::istream errorStream(&errorBuf);
- if (!checkOutput(outputStream, errorStream)) {
- return false;
- }
- return true;
- }
- bool testUVProcessChainNone(const char* helperCommand)
- {
- cmUVProcessChainBuilder builder;
- std::unique_ptr<cmUVProcessChain> chain;
- builder.AddCommand({ helperCommand, "echo" })
- .AddCommand({ helperCommand, "capitalize" })
- .AddCommand({ helperCommand, "dedup" });
- if (!checkExecution(builder, chain)) {
- return false;
- }
- if (chain->OutputStream()) {
- std::cout << "OutputStream() was not null, expecting null" << std::endl;
- return false;
- }
- if (chain->ErrorStream()) {
- std::cout << "ErrorStream() was not null, expecting null" << std::endl;
- return false;
- }
- return true;
- }
- int testUVProcessChain(int argc, char** const argv)
- {
- if (argc < 2) {
- std::cout << "Invalid arguments.\n";
- return -1;
- }
- if (!testUVProcessChainBuiltin(argv[1])) {
- std::cout << "While executing testUVProcessChainBuiltin().\n";
- return -1;
- }
- if (!testUVProcessChainExternal(argv[1])) {
- std::cout << "While executing testUVProcessChainExternal().\n";
- return -1;
- }
- if (!testUVProcessChainNone(argv[1])) {
- std::cout << "While executing testUVProcessChainNone().\n";
- return -1;
- }
- return 0;
- }
|