testUVProcessChain.cxx 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724
  1. #include <algorithm>
  2. #include <csignal>
  3. #include <cstdio>
  4. #include <functional>
  5. #include <iostream>
  6. #include <sstream>
  7. #include <string>
  8. #include <utility>
  9. #include <vector>
  10. #include <cm/memory>
  11. #include <cm3p/uv.h>
  12. #include "cm_fileno.hxx"
  13. #include "cmGetPipes.h"
  14. #include "cmStringAlgorithms.h"
  15. #include "cmUVHandlePtr.h"
  16. #include "cmUVProcessChain.h"
  17. #include "cmUVStream.h"
  18. #include "cmUVStreambuf.h"
  19. struct ExpectedStatus
  20. {
  21. bool MatchExitStatus;
  22. bool MatchTermSignal;
  23. cmUVProcessChain::Status Status;
  24. cmUVProcessChain::ExceptionCode ExceptionCode;
  25. std::string ExceptionString;
  26. };
  27. static const char* ExceptionCodeToString(cmUVProcessChain::ExceptionCode code)
  28. {
  29. switch (code) {
  30. case cmUVProcessChain::ExceptionCode::None:
  31. return "None";
  32. case cmUVProcessChain::ExceptionCode::Fault:
  33. return "Fault";
  34. case cmUVProcessChain::ExceptionCode::Illegal:
  35. return "Illegal";
  36. case cmUVProcessChain::ExceptionCode::Interrupt:
  37. return "Interrupt";
  38. case cmUVProcessChain::ExceptionCode::Numerical:
  39. return "Numerical";
  40. case cmUVProcessChain::ExceptionCode::Spawn:
  41. return "Spawn";
  42. case cmUVProcessChain::ExceptionCode::Other:
  43. return "Other";
  44. default:
  45. return "";
  46. }
  47. }
  48. bool operator==(const cmUVProcessChain::Status* actual,
  49. const ExpectedStatus& expected)
  50. {
  51. if (expected.Status.SpawnResult != actual->SpawnResult) {
  52. return false;
  53. }
  54. if (expected.Status.Finished != actual->Finished) {
  55. return false;
  56. }
  57. if (expected.MatchExitStatus &&
  58. expected.Status.ExitStatus != actual->ExitStatus) {
  59. return false;
  60. }
  61. if (expected.MatchTermSignal &&
  62. expected.Status.TermSignal != actual->TermSignal) {
  63. return false;
  64. }
  65. if (expected.Status.Finished &&
  66. std::make_pair(expected.ExceptionCode, expected.ExceptionString) !=
  67. actual->GetException()) {
  68. return false;
  69. }
  70. return true;
  71. }
  72. static bool resultsMatch(
  73. const std::vector<const cmUVProcessChain::Status*>& actual,
  74. const std::vector<ExpectedStatus>& expected)
  75. {
  76. return actual.size() == expected.size() &&
  77. std::equal(actual.begin(), actual.end(), expected.begin());
  78. }
  79. static std::string getInput(std::istream& input)
  80. {
  81. char buffer[1024];
  82. std::ostringstream str;
  83. do {
  84. input.read(buffer, 1024);
  85. str.write(buffer, input.gcount());
  86. } while (input.gcount() > 0);
  87. return str.str();
  88. }
  89. template <typename T>
  90. std::function<std::ostream&(std::ostream&)> printExpected(bool match,
  91. const T& value)
  92. {
  93. return [match, value](std::ostream& stream) -> std::ostream& {
  94. if (match) {
  95. stream << value;
  96. } else {
  97. stream << "*";
  98. }
  99. return stream;
  100. };
  101. }
  102. std::ostream& operator<<(
  103. std::ostream& stream,
  104. const std::function<std::ostream&(std::ostream&)>& func)
  105. {
  106. return func(stream);
  107. }
  108. static void printResults(
  109. const std::vector<const cmUVProcessChain::Status*>& actual,
  110. const std::vector<ExpectedStatus>& expected)
  111. {
  112. std::cout << "Expected: " << std::endl;
  113. for (auto const& e : expected) {
  114. std::cout << " SpawnResult: " << e.Status.SpawnResult
  115. << ", Finished: " << e.Status.Finished << ", ExitStatus: "
  116. << printExpected(e.MatchExitStatus, e.Status.ExitStatus)
  117. << ", TermSignal: "
  118. << printExpected(e.MatchTermSignal, e.Status.TermSignal)
  119. << ", ExceptionCode: "
  120. << printExpected(e.Status.Finished,
  121. ExceptionCodeToString(e.ExceptionCode))
  122. << ", ExceptionString: \""
  123. << printExpected(e.Status.Finished, e.ExceptionString) << '"'
  124. << std::endl;
  125. }
  126. std::cout << "Actual:" << std::endl;
  127. for (auto const& a : actual) {
  128. auto exception = a->GetException();
  129. std::cout << " SpawnResult: " << a->SpawnResult
  130. << ", Finished: " << a->Finished
  131. << ", ExitStatus: " << a->ExitStatus
  132. << ", TermSignal: " << a->TermSignal
  133. << ", ExceptionCode: " << ExceptionCodeToString(exception.first)
  134. << ", ExceptionString: \"" << exception.second << '"'
  135. << std::endl;
  136. }
  137. }
  138. static bool checkExecution(cmUVProcessChainBuilder& builder,
  139. std::unique_ptr<cmUVProcessChain>& chain)
  140. {
  141. static const std::vector<ExpectedStatus> status1 = {
  142. { false,
  143. false,
  144. { 0, false, 0, 0 },
  145. cmUVProcessChain::ExceptionCode::None,
  146. "" },
  147. { false,
  148. false,
  149. { 0, false, 0, 0 },
  150. cmUVProcessChain::ExceptionCode::None,
  151. "" },
  152. { false,
  153. false,
  154. { 0, false, 0, 0 },
  155. cmUVProcessChain::ExceptionCode::None,
  156. "" },
  157. };
  158. static const std::vector<ExpectedStatus> status2 = {
  159. { true,
  160. true,
  161. { 0, true, 0, 0 },
  162. cmUVProcessChain::ExceptionCode::None,
  163. "" },
  164. { false,
  165. false,
  166. { 0, false, 0, 0 },
  167. cmUVProcessChain::ExceptionCode::None,
  168. "" },
  169. { false,
  170. false,
  171. { 0, false, 0, 0 },
  172. cmUVProcessChain::ExceptionCode::None,
  173. "" },
  174. };
  175. static const std::vector<ExpectedStatus> status3 = {
  176. { true,
  177. true,
  178. { 0, true, 0, 0 },
  179. cmUVProcessChain::ExceptionCode::None,
  180. "" },
  181. { true,
  182. true,
  183. { 0, true, 1, 0 },
  184. cmUVProcessChain::ExceptionCode::None,
  185. "" },
  186. #ifdef _WIN32
  187. { true,
  188. true,
  189. { 0, true, STATUS_ACCESS_VIOLATION, 0 },
  190. cmUVProcessChain::ExceptionCode::Fault,
  191. "Access violation" },
  192. #else
  193. { false,
  194. true,
  195. { 0, true, 0, SIGABRT },
  196. cmUVProcessChain::ExceptionCode::Other,
  197. "Subprocess aborted" },
  198. #endif
  199. };
  200. std::vector<const cmUVProcessChain::Status*> status;
  201. chain = cm::make_unique<cmUVProcessChain>(builder.Start());
  202. if (!chain->Valid()) {
  203. std::cout << "Valid() returned false, should be true" << std::endl;
  204. return false;
  205. }
  206. status = chain->GetStatus();
  207. if (!resultsMatch(status, status1)) {
  208. std::cout << "GetStatus() did not produce expected output" << std::endl;
  209. printResults(status, status1);
  210. return false;
  211. }
  212. if (chain->Finished()) {
  213. std::cout << "Finished() returned true, should be false" << std::endl;
  214. return false;
  215. }
  216. if (chain->Wait(9000)) {
  217. std::cout << "Wait() returned true, should be false" << std::endl;
  218. return false;
  219. }
  220. status = chain->GetStatus();
  221. if (!resultsMatch(status, status2)) {
  222. std::cout << "GetStatus() did not produce expected output" << std::endl;
  223. printResults(status, status2);
  224. return false;
  225. }
  226. if (chain->Finished()) {
  227. std::cout << "Finished() returned true, should be false" << std::endl;
  228. return false;
  229. }
  230. if (!chain->Wait()) {
  231. std::cout << "Wait() returned false, should be true" << std::endl;
  232. return false;
  233. }
  234. status = chain->GetStatus();
  235. if (!resultsMatch(status, status3)) {
  236. std::cout << "GetStatus() did not produce expected output" << std::endl;
  237. printResults(status, status3);
  238. return false;
  239. }
  240. if (!chain->Finished()) {
  241. std::cout << "Finished() returned false, should be true" << std::endl;
  242. return false;
  243. }
  244. return true;
  245. }
  246. static bool checkOutput(std::istream& outputStream, std::istream& errorStream)
  247. {
  248. std::string output = getInput(outputStream);
  249. if (output != "HELO WRD!") {
  250. std::cout << "Output was \"" << output << "\", expected \"HELO WRD!\""
  251. << std::endl;
  252. return false;
  253. }
  254. std::string error = getInput(errorStream);
  255. auto qemu_error_pos = error.find("qemu:");
  256. if (qemu_error_pos != std::string::npos) {
  257. error.resize(qemu_error_pos);
  258. }
  259. if (error.length() != 3 || error.find('1') == std::string::npos ||
  260. error.find('2') == std::string::npos ||
  261. error.find('3') == std::string::npos) {
  262. std::cout << "Error was \"" << error << "\", expected \"123\""
  263. << std::endl;
  264. return false;
  265. }
  266. return true;
  267. }
  268. bool testUVProcessChainBuiltin(const char* helperCommand)
  269. {
  270. cmUVProcessChainBuilder builder;
  271. std::unique_ptr<cmUVProcessChain> chain;
  272. builder.AddCommand({ helperCommand, "echo" })
  273. .AddCommand({ helperCommand, "capitalize" })
  274. .AddCommand({ helperCommand, "dedup" })
  275. .SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
  276. .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR);
  277. if (!checkExecution(builder, chain)) {
  278. return false;
  279. }
  280. if (chain->OutputStream() < 0) {
  281. std::cout << "OutputStream() was invalid, expecting valid" << std::endl;
  282. return false;
  283. }
  284. if (chain->ErrorStream() < 0) {
  285. std::cout << "ErrorStream() was invalid, expecting valid" << std::endl;
  286. return false;
  287. }
  288. cmUVPipeIStream output(chain->GetLoop(), chain->OutputStream());
  289. cmUVPipeIStream error(chain->GetLoop(), chain->ErrorStream());
  290. if (!checkOutput(output, error)) {
  291. return false;
  292. }
  293. return true;
  294. }
  295. bool testUVProcessChainBuiltinMerged(const char* helperCommand)
  296. {
  297. cmUVProcessChainBuilder builder;
  298. std::unique_ptr<cmUVProcessChain> chain;
  299. builder.AddCommand({ helperCommand, "echo" })
  300. .AddCommand({ helperCommand, "capitalize" })
  301. .AddCommand({ helperCommand, "dedup" })
  302. .SetMergedBuiltinStreams();
  303. if (!checkExecution(builder, chain)) {
  304. return false;
  305. }
  306. if (chain->OutputStream() < 0) {
  307. std::cout << "OutputStream() was invalid, expecting valid" << std::endl;
  308. return false;
  309. }
  310. if (chain->ErrorStream() < 0) {
  311. std::cout << "ErrorStream() was invalid, expecting valid" << std::endl;
  312. return false;
  313. }
  314. if (chain->OutputStream() != chain->ErrorStream()) {
  315. std::cout << "OutputStream() and ErrorStream() expected to be the same"
  316. << std::endl;
  317. return false;
  318. }
  319. cmUVPipeIStream mergedStream(chain->GetLoop(), chain->OutputStream());
  320. std::string merged = getInput(mergedStream);
  321. auto qemuErrorPos = merged.find("qemu:");
  322. if (qemuErrorPos != std::string::npos) {
  323. merged.resize(qemuErrorPos);
  324. }
  325. if (merged.length() != cmStrLen("HELO WRD!123") ||
  326. merged.find('1') == std::string::npos ||
  327. merged.find('2') == std::string::npos ||
  328. merged.find('3') == std::string::npos) {
  329. std::cout << "Expected output to contain '1', '2', and '3', was \""
  330. << merged << "\"" << std::endl;
  331. return false;
  332. }
  333. std::string output;
  334. for (auto const& c : merged) {
  335. if (c != '1' && c != '2' && c != '3') {
  336. output += c;
  337. }
  338. }
  339. if (output != "HELO WRD!") {
  340. std::cout << "Output was \"" << output << "\", expected \"HELO WRD!\""
  341. << std::endl;
  342. return false;
  343. }
  344. return true;
  345. }
  346. bool testUVProcessChainExternal(const char* helperCommand)
  347. {
  348. cmUVProcessChainBuilder builder;
  349. std::unique_ptr<cmUVProcessChain> chain;
  350. int outputPipe[2], errorPipe[2];
  351. cm::uv_pipe_ptr outputInPipe, outputOutPipe, errorInPipe, errorOutPipe;
  352. if (cmGetPipes(outputPipe) < 0) {
  353. std::cout << "Error creating pipes" << std::endl;
  354. return false;
  355. }
  356. if (cmGetPipes(errorPipe) < 0) {
  357. std::cout << "Error creating pipes" << std::endl;
  358. return false;
  359. }
  360. builder.AddCommand({ helperCommand, "echo" })
  361. .AddCommand({ helperCommand, "capitalize" })
  362. .AddCommand({ helperCommand, "dedup" })
  363. .SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT, outputPipe[1])
  364. .SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR, errorPipe[1]);
  365. if (!checkExecution(builder, chain)) {
  366. return false;
  367. }
  368. if (chain->OutputStream() >= 0) {
  369. std::cout << "OutputStream() was valid, expecting invalid" << std::endl;
  370. return false;
  371. }
  372. if (chain->ErrorStream() >= 0) {
  373. std::cout << "ErrorStream() was valid, expecting invalid" << std::endl;
  374. return false;
  375. }
  376. outputOutPipe.init(chain->GetLoop(), 0);
  377. uv_pipe_open(outputOutPipe, outputPipe[1]);
  378. outputOutPipe.reset();
  379. errorOutPipe.init(chain->GetLoop(), 0);
  380. uv_pipe_open(errorOutPipe, errorPipe[1]);
  381. errorOutPipe.reset();
  382. outputInPipe.init(chain->GetLoop(), 0);
  383. uv_pipe_open(outputInPipe, outputPipe[0]);
  384. cmUVStreambuf outputBuf;
  385. outputBuf.open(outputInPipe);
  386. std::istream outputStream(&outputBuf);
  387. errorInPipe.init(chain->GetLoop(), 0);
  388. uv_pipe_open(errorInPipe, errorPipe[0]);
  389. cmUVStreambuf errorBuf;
  390. errorBuf.open(errorInPipe);
  391. std::istream errorStream(&errorBuf);
  392. if (!checkOutput(outputStream, errorStream)) {
  393. return false;
  394. }
  395. return true;
  396. }
  397. bool testUVProcessChainNone(const char* helperCommand)
  398. {
  399. cmUVProcessChainBuilder builder;
  400. std::unique_ptr<cmUVProcessChain> chain;
  401. builder.AddCommand({ helperCommand, "echo" })
  402. .AddCommand({ helperCommand, "capitalize" })
  403. .AddCommand({ helperCommand, "dedup" });
  404. if (!checkExecution(builder, chain)) {
  405. return false;
  406. }
  407. if (chain->OutputStream() >= 0) {
  408. std::cout << "OutputStream() was valid, expecting invalid" << std::endl;
  409. return false;
  410. }
  411. if (chain->ErrorStream() >= 0) {
  412. std::cout << "ErrorStream() was valid, expecting invalid" << std::endl;
  413. return false;
  414. }
  415. return true;
  416. }
  417. bool testUVProcessChainCwdUnchanged(const char* helperCommand)
  418. {
  419. cmUVProcessChainBuilder builder;
  420. builder.AddCommand({ helperCommand, "pwd" })
  421. .SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
  422. .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR);
  423. auto chain = builder.Start();
  424. chain.Wait();
  425. if (chain.GetStatus().front()->ExitStatus != 0) {
  426. std::cout << "Exit status was " << chain.GetStatus().front()->ExitStatus
  427. << ", expecting 0" << std::endl;
  428. return false;
  429. }
  430. cmUVPipeIStream output(chain.GetLoop(), chain.OutputStream());
  431. auto cwd = getInput(output);
  432. if (!cmHasLiteralSuffix(cwd, "/Tests/CMakeLib")) {
  433. std::cout << "Working directory was \"" << cwd
  434. << "\", expected to end in \"/Tests/CMakeLib\"" << std::endl;
  435. return false;
  436. }
  437. return true;
  438. }
  439. bool testUVProcessChainCwdChanged(const char* helperCommand)
  440. {
  441. cmUVProcessChainBuilder builder;
  442. builder.AddCommand({ helperCommand, "pwd" })
  443. .SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
  444. .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR)
  445. .SetWorkingDirectory("..");
  446. auto chain = builder.Start();
  447. chain.Wait();
  448. if (chain.GetStatus().front()->ExitStatus != 0) {
  449. std::cout << "Exit status was " << chain.GetStatus().front()->ExitStatus
  450. << ", expecting 0" << std::endl;
  451. return false;
  452. }
  453. cmUVPipeIStream output(chain.GetLoop(), chain.OutputStream());
  454. auto cwd = getInput(output);
  455. if (!cmHasLiteralSuffix(cwd, "/Tests")) {
  456. std::cout << "Working directory was \"" << cwd
  457. << "\", expected to end in \"/Tests\"" << std::endl;
  458. return false;
  459. }
  460. return true;
  461. }
  462. bool testUVProcessChainSpawnFail(const char* helperCommand)
  463. {
  464. static const std::vector<ExpectedStatus> status1 = {
  465. { false,
  466. false,
  467. { 0, false, 0, 0 },
  468. cmUVProcessChain::ExceptionCode::None,
  469. "" },
  470. { false,
  471. false,
  472. { UV_ENOENT, true, 0, 0 },
  473. cmUVProcessChain::ExceptionCode::Spawn,
  474. uv_strerror(UV_ENOENT) },
  475. #ifdef _WIN32
  476. { true,
  477. true,
  478. { 0, true, STATUS_ACCESS_VIOLATION, 0 },
  479. cmUVProcessChain::ExceptionCode::Fault,
  480. "Access violation" },
  481. #else
  482. { false,
  483. true,
  484. { 0, true, 0, SIGABRT },
  485. cmUVProcessChain::ExceptionCode::Other,
  486. "Subprocess aborted" },
  487. #endif
  488. };
  489. static const std::vector<ExpectedStatus> status2 = {
  490. #ifdef _WIN32
  491. { true,
  492. true,
  493. { 0, true, 0, 0 },
  494. cmUVProcessChain::ExceptionCode::None,
  495. "" },
  496. #else
  497. { false,
  498. true,
  499. { 0, true, 0, SIGPIPE },
  500. cmUVProcessChain::ExceptionCode::Other,
  501. "SIGPIPE" },
  502. #endif
  503. { false,
  504. false,
  505. { UV_ENOENT, true, 0, 0 },
  506. cmUVProcessChain::ExceptionCode::Spawn,
  507. uv_strerror(UV_ENOENT) },
  508. #ifdef _WIN32
  509. { true,
  510. true,
  511. { 0, true, STATUS_ACCESS_VIOLATION, 0 },
  512. cmUVProcessChain::ExceptionCode::Fault,
  513. "Access violation" },
  514. #else
  515. { false,
  516. true,
  517. { 0, true, 0, SIGABRT },
  518. cmUVProcessChain::ExceptionCode::Other,
  519. "Subprocess aborted" },
  520. #endif
  521. };
  522. std::vector<const cmUVProcessChain::Status*> status;
  523. cmUVProcessChainBuilder builder;
  524. builder.AddCommand({ helperCommand, "echo" })
  525. .AddCommand({ "this_command_is_for_cmake_and_should_never_exist" })
  526. .AddCommand({ helperCommand, "dedup" })
  527. .SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
  528. .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR);
  529. auto chain = builder.Start();
  530. if (!chain.Valid()) {
  531. std::cout << "Valid() returned false, should be true" << std::endl;
  532. return false;
  533. }
  534. // Some platforms, like Solaris 10, take a long time to report a trapped
  535. // subprocess to the parent process (about 1.7 seconds in the case of
  536. // Solaris 10.) Wait 3 seconds to give it enough time.
  537. if (chain.Wait(3000)) {
  538. std::cout << "Wait() did not time out" << std::endl;
  539. return false;
  540. }
  541. status = chain.GetStatus();
  542. if (!resultsMatch(status, status1)) {
  543. std::cout << "GetStatus() did not produce expected output" << std::endl;
  544. printResults(status, status1);
  545. return false;
  546. }
  547. if (!chain.Wait()) {
  548. std::cout << "Wait() timed out" << std::endl;
  549. return false;
  550. }
  551. status = chain.GetStatus();
  552. if (!resultsMatch(status, status2)) {
  553. std::cout << "GetStatus() did not produce expected output" << std::endl;
  554. printResults(status, status2);
  555. return false;
  556. }
  557. return true;
  558. }
  559. bool testUVProcessChainInputFile(const char* helperCommand)
  560. {
  561. std::unique_ptr<FILE, int (*)(FILE*)> f(
  562. fopen("testUVProcessChainInput.txt", "rb"), fclose);
  563. cmUVProcessChainBuilder builder;
  564. builder.AddCommand({ helperCommand, "dedup" })
  565. .SetExternalStream(cmUVProcessChainBuilder::Stream_INPUT,
  566. cm_fileno(f.get()))
  567. .SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT);
  568. auto chain = builder.Start();
  569. if (!chain.Wait()) {
  570. std::cout << "Wait() timed out" << std::endl;
  571. return false;
  572. }
  573. cmUVPipeIStream stream(chain.GetLoop(), chain.OutputStream());
  574. std::string output = getInput(stream);
  575. if (output != "HELO WRD!") {
  576. std::cout << "Output was \"" << output << "\", expected \"HELO WRD!\""
  577. << std::endl;
  578. return false;
  579. }
  580. return true;
  581. }
  582. bool testUVProcessChainWait0(const char* helperCommand)
  583. {
  584. cmUVProcessChainBuilder builder;
  585. builder.AddCommand({ helperCommand, "echo" });
  586. auto chain = builder.Start();
  587. if (!chain.Wait(0)) {
  588. std::cout << "Wait(0) returned false, should be true" << std::endl;
  589. return false;
  590. }
  591. return true;
  592. }
  593. int testUVProcessChain(int argc, char** const argv)
  594. {
  595. if (argc < 2) {
  596. std::cout << "Invalid arguments.\n";
  597. return -1;
  598. }
  599. if (!testUVProcessChainBuiltin(argv[1])) {
  600. std::cout << "While executing testUVProcessChainBuiltin().\n";
  601. return -1;
  602. }
  603. if (!testUVProcessChainBuiltinMerged(argv[1])) {
  604. std::cout << "While executing testUVProcessChainBuiltinMerged().\n";
  605. return -1;
  606. }
  607. if (!testUVProcessChainExternal(argv[1])) {
  608. std::cout << "While executing testUVProcessChainExternal().\n";
  609. return -1;
  610. }
  611. if (!testUVProcessChainNone(argv[1])) {
  612. std::cout << "While executing testUVProcessChainNone().\n";
  613. return -1;
  614. }
  615. if (!testUVProcessChainCwdUnchanged(argv[1])) {
  616. std::cout << "While executing testUVProcessChainCwdUnchanged().\n";
  617. return -1;
  618. }
  619. if (!testUVProcessChainCwdChanged(argv[1])) {
  620. std::cout << "While executing testUVProcessChainCwdChanged().\n";
  621. return -1;
  622. }
  623. if (!testUVProcessChainSpawnFail(argv[1])) {
  624. std::cout << "While executing testUVProcessChainSpawnFail().\n";
  625. return -1;
  626. }
  627. if (!testUVProcessChainInputFile(argv[1])) {
  628. std::cout << "While executing testUVProcessChainInputFile().\n";
  629. return -1;
  630. }
  631. if (!testUVProcessChainWait0(argv[1])) {
  632. std::cout << "While executing testUVProcessChainWait0().\n";
  633. return -1;
  634. }
  635. return 0;
  636. }