1 #include <TTestSuite.h>
5 * Create a new s_TestSuite an returns a pointer to self.
7 TestSuite_t TestSuite_new(void)
9 TestSuite_t testSuite = calloc(1, sizeof(s_TestSuite_t));
11 if (NULL == testSuite) {
12 setErrno(E_TEST_SUITE_ALLOCATION_FAILED);
13 TestSuite_free(testSuite);
17 testSuite->stream = Stream_new();
19 if (NULL == testSuite->stream) {
20 TestSuite_free(testSuite);
24 testSuite->test_case_context = TestCaseContext_new();
26 if (NULL == testSuite->test_case_context) {
27 TestSuite_free(testSuite);
31 testSuite->test_case_context->hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
33 testSuite->threads = ThreadDynarray_new(15);
35 if (NULL == testSuite->threads) {
36 TestSuite_free(testSuite);
40 testSuite->successCount = 0;
41 testSuite->failureCount = 0;
47 * Initialize the s_TestSuite structure.
49 errno_t TestSuite_initialize(TestSuite_t ptr, int argc, char *argv[])
53 TestSuite_print("Run the test case from the console.\n");
55 ptr->stream->file = stdin;
60 if (E_SUCCESS != Stream_isValidFile(argv[1]))
63 printf("\n\n Test runner : %s\n\n", argv[1]);
65 if (E_SUCCESS != Stream_openFile(ptr->stream, argv[1]))
72 setErrno(E_BAD_USAGE);
79 * Launch the test suite.
81 void TestSuite_run(TestSuite_t testSuite)
83 Stream_t stream = testSuite->stream;
85 /* Handle all lines in the testsuite file (or from stdin) */
86 while ((Stream_getLine(stream) != -1) && (E_SUCCESS == getErrno())) {
87 /* Don't process blank lines. */
88 if (Stream_lineIsBlank(stream))
91 /* Check if the current text line contains a invalid token. */
92 if (Stream_lineContainsInvalidToken(stream))
95 /* Check if the text line contains a meta command. */
96 if (Stream_lineIsMetaCommand(stream)) {
97 /* Check if the current text line contains a unknown meta command. */
98 if (Stream_lineIsUnknwnMetaCommand(stream))
101 /* Check the meta command validity. */
102 if (Stream_lineIsInvalidMetaCommand(stream))
105 /* We have a valid meta command, process it */
106 if (E_SUCCESS != TestSuite_processMetaCommand(testSuite))
112 /* Handle the comment. */
113 if (Stream_lineIsComment(stream)) {
114 Stream_printLine(testSuite->stream, comment_line_type);
118 /* Handle expected child output. */
119 if (Stream_lineIsExpectedChildOutput(stream)) {
120 if (E_SUCCESS != TestSuite_processExpectedChildOutput(testSuite))
126 /* Handle expected child input. */
127 if (Stream_lineIsChildInput(stream)) {
128 if (E_SUCCESS != TestSuite_processChildInput(testSuite))
134 if (Stream_lineIsChangeDir(stream)) {
135 if (E_SUCCESS != TestSuite_changeDir(testSuite))
141 /* Handle synchrone synchrone test case. */
142 if (Stream_lineIsSyncTestCase(stream)) {
143 TestCaseContext_setName(testSuite->test_case_context,
146 TestSuite_runSyncTestCase(testSuite->test_case_context);
149 if (TestSuite_iSPostOutputCheckingEnabled
150 (testSuite->test_case_context)) {
151 TestSuite_checkChildOutput(testSuite->test_case_context);
154 if (TestSuite_iSExitCodeCheckingEnabled
155 (testSuite->test_case_context)) {
157 TestSuite_checkChildExitCode(testSuite->test_case_context))
162 if (E_SUCCESS != getErrno())
165 /* Handle asynchrone synchrone test case. */
166 else if (Stream_lineIsAsyncTestCase(stream)) {
167 TestCaseContext_setName(testSuite->test_case_context,
170 if (E_SUCCESS != TestSuite_runAsyncTestCase(testSuite))
176 /* Clear the child input stream. */
177 Buffer_clear(testSuite->test_case_context->inputBuffer);
178 /* Clear the command line buffer. */
179 Buffer_clear(testSuite->test_case_context->commandLineBuffer);
184 * Meta command processing.
186 errno_t TestSuite_processMetaCommand(TestSuite_t testSuite)
188 Stream_t stream = testSuite->stream;
190 if (!strncmp("set timeout ", stream->line + 2, strlen("set timeout "))) {
191 TestSuite_setTimeout(testSuite);
194 ("command line ", stream->line + 2, strlen("command line"))) {
195 TestSuite_setCommandLine(testSuite);
198 ("enable output checking", stream->line + 2,
199 strlen("enable output checking"))) {
200 TestSuite_enableOutputChecking(testSuite);
203 ("disable output checking", stream->line + 2,
204 strlen("disable output checking"))) {
205 TestSuite_disableOutputChecking(testSuite);
208 ("enable post output checking", stream->line + 2,
209 strlen("enable post output checking"))) {
210 TestSuite_enablePostOutputChecking(testSuite);
213 ("disable post output checking", stream->line + 2,
214 strlen("disable post output checking"))) {
215 TestSuite_disablePostOutputChecking(testSuite);
218 ("expect exit code ", stream->line + 2,
219 strlen("expect exit code "))) {
220 TestSuite_setExpectedExitCode(testSuite);
221 } else if (!strncmp("export ", stream->line + 2, strlen("export "))) {
222 TestSuite_export(testSuite);
223 } else if (!strncmp("unset ", stream->line + 2, strlen("unset "))) {
224 TestSuite_unset(testSuite);
227 ("create console", stream->line + 2, strlen("create console"))) {
228 TestSuite_createConsole(testSuite);
231 ("create no console", stream->line + 2,
232 strlen("create no console"))) {
233 TestSuite_createNoConsole(testSuite);
236 ("enable exit code checking", stream->line + 2,
237 strlen("enable exit code checking"))) {
238 TestSuite_enableExitCodeChecking(testSuite);
241 ("disable exit code checking", stream->line + 2,
242 strlen("disable exit code checking"))) {
243 TestSuite_disableExitCodeChecking(testSuite);
254 * Set the timeout of the test case context of the
257 void TestSuite_setTimeout(TestSuite_t testSuite)
260 int timeout = atoi(testSuite->stream->line + 2 + strlen("set timeout "));
261 TestCaseContext_setTimeout(testSuite->test_case_context, timeout);
265 * Enable output checking for the current test case context.
267 void TestSuite_enableOutputChecking(TestSuite_t testSuite)
269 TestCaseContext_enableOutputChecking(testSuite->test_case_context);
272 void TestSuite_setCommandLine(TestSuite_t testSuite)
274 TestCaseContext_setCommandLine(testSuite->test_case_context,
275 testSuite->stream->line + 2 +
276 strlen("command line "));
280 * Disable output checking for the current test case context.
282 void TestSuite_disableOutputChecking(TestSuite_t testSuite)
284 TestCaseContext_disableOutputChecking(testSuite->test_case_context);
288 * Enable post output checking for the current test case context.
290 void TestSuite_enablePostOutputChecking(TestSuite_t testSuite)
292 TestCaseContext_enable_post_output_checking(testSuite->
296 void TestSuite_createConsole(TestSuite_t testSuite)
298 TestCaseContext_createConsole(testSuite->test_case_context);
301 void TestSuite_createNoConsole(TestSuite_t testSuite)
303 TestCaseContext_createNoConsole(testSuite->test_case_context);
307 * Disable post output checking for the current test case context.
309 void TestSuite_disablePostOutputChecking(TestSuite_t testSuite)
311 TestCaseContext_disablePostOutputChecking(testSuite->test_case_context);
315 * Set the expected exit code of the current test case context of the test suite.
317 void TestSuite_setExpectedExitCode(TestSuite_t testSuite)
319 int expectedExitCode =
320 atoi(testSuite->stream->line + 2 + strlen("expect exit code "));
321 TestCaseContext_setExpectedExitCode(testSuite->test_case_context,
325 void TestSuite_enableExitCodeChecking(TestSuite_t testSuite)
327 TestCaseContext_enableExitCodeChecking(testSuite->test_case_context);
330 void TestSuite_disableExitCodeChecking(TestSuite_t testSuite)
332 TestCaseContext_disableExitCodeChecking(testSuite->test_case_context);
337 * Export a variable in the environment of the current test_runner.exe process.
339 errno_t TestSuite_export(TestSuite_t testSuite)
344 char __buffer[50] = { 0 };
345 char *line = testSuite->stream->line + strlen("export ");
347 line[strlen(line) - 1] = '\0';
349 ptr = strchr(line, ' ');
351 ptr = strchr(line, '=');
352 strncpy(__buffer, pos, ptr - pos);
353 if (!SetEnvironmentVariable(__buffer, ++ptr)) {
354 setErrno(E_EXPORT_FAILED);
355 Stream_printLine(testSuite->stream, export_failed_line_type);
363 errno_t TestSuite_unset(TestSuite_t testSuite)
365 char line[128] = { 0 };
367 strcpy(line, testSuite->stream->line + 2);
368 ptr = strchr(line, ' ');
369 line[strlen(line) - 1] = '\0';
371 if (!SetEnvironmentVariable(++ptr, NULL)) {
373 setErrno(E_UNSET_FAILED);
374 Stream_printLine(testSuite->stream, unset_failed_line_type);
382 * Expected child output processing.
384 errno_t TestSuite_processExpectedChildOutput(TestSuite_t testSuite)
386 /* TODO : logic error */
387 if (!TestCaseContext_isOutputCheckingEnabled
388 (testSuite->test_case_context))
392 TestCaseContext_appendExpectedOutput(testSuite->test_case_context,
393 testSuite->stream->line + 2);
399 * Child input processing.
401 errno_t TestSuite_processChildInput(TestSuite_t testSuite)
404 TestCaseContext_appendChildInput(testSuite->test_case_context,
405 testSuite->stream->line + 2);
411 * Free the s_TestSuite pointed to by ptr.
413 void TestSuite_free(TestSuite_t testSuite)
420 bool last_async_process_error = false;
422 errno_t e = getErrno();
424 if (NULL == testSuite)
427 count = ThreadDynarray_getCount(testSuite->threads);
429 /* Wait for all asynchrone process */
430 if (NULL != testSuite->threads && count) {
432 steel_running = false;
434 for (i = 0; i < count; i++) {
435 entry = ThreadDynarray_at(testSuite->threads, i);
437 GetExitCodeThread(entry->hThread, &ExitCode);
439 if (STILL_ACTIVE == ExitCode) {
441 steel_running = true;
449 for (i = 0; i < count; i++) {
450 entry = ThreadDynarray_at(testSuite->threads, i);
452 if (entry->context->pi.hProcess) {
453 dwWaitResult = WaitForSingleObject(entry->hThread, INFINITE);
455 if ((WAIT_FAILED == dwWaitResult))
456 TerminateThread(entry->hThread, 0);
458 CloseHandle(entry->hThread);
461 /*if(((E_SUCCESS == e) || (E_EXIT_CODE_DONT_MATCH == e) || (E_OUTPUT_DONT_MATCH == e)) && !last_async_process_error)
463 /* Child output and exit code checking */
464 if (TestSuite_iSPostOutputCheckingEnabled(entry->context)) {
465 if (E_SUCCESS != TestSuite_checkChildOutput(entry->context))
466 last_async_process_error = true;
469 if (TestSuite_iSExitCodeCheckingEnabled(entry->context)) {
470 if (E_SUCCESS != TestSuite_checkChildExitCode(entry->context))
471 last_async_process_error = true;
475 TestCaseContext_free(entry->context);
478 ThreadDynarray_destroy(testSuite->threads);
481 if (NULL != testSuite->test_case_context)
482 TestCaseContext_free(testSuite->test_case_context);
484 if (NULL != testSuite->stream)
485 Stream_free(testSuite->stream);
491 * Check the child output.
493 errno_t TestSuite_checkChildOutput(TestCaseContext_t context)
495 bool are_equals = false;
496 char str[256] = { 0 };
499 if (context->expectedOutputBuffer->size == 0
500 && context->outputBuffer->size == 0)
503 Buffer_chomp(context->outputBuffer);
504 Buffer_chomp(context->expectedOutputBuffer);
507 if (context->outputBuffer->size != context->expectedOutputBuffer->size
508 || strcmp(context->outputBuffer->data,
509 context->expectedOutputBuffer->data)) {
510 strcpy(str, "<OUTPUT NOT MATCH > \n");
511 TestSuite_print(str);
515 strcpy(str, "<OUTPUT MATCH > \n");
516 TestSuite_print(str);
523 if (context->expectedOutputBuffer->size) {
525 "<EXPECTED > SIZE (%4d) DATA (%s)\n",
526 context->expectedOutputBuffer->size,
527 context->expectedOutputBuffer->data);
528 TestSuite_print(str);
531 "<EXPECTED > SIZE (%4d) DATA (%s)\n",
532 context->expectedOutputBuffer->size, "empty");
533 TestSuite_print(str);
538 if (context->outputBuffer->size) {
540 "<RECEIVED > SIZE (%4d) DATA (%s)\n",
541 context->outputBuffer->size, context->outputBuffer->data);
542 TestSuite_print(str);
545 "<RECEIVED > SIZE (%4d) DATA (%s)\n",
546 context->outputBuffer->size, "empty");
547 TestSuite_print(str);
550 Buffer_clear(context->expectedOutputBuffer);
551 Buffer_clear(context->outputBuffer);
554 setErrno(E_OUTPUT_DONT_MATCH);
562 * Check the child process exit code.
564 errno_t TestSuite_checkChildExitCode(TestCaseContext_t context)
566 bool __success = false;
567 char str[256] = { 0 };
569 sprintf(str, "<TEST CASE TERMINATED > %s %3ld\n",
570 context->name, context->exitCode);
571 TestSuite_print(str);
575 /* if a expected exit code was signaled, compare it with the real. */
576 if (context->expectedExitCode != INVALID_EXIT_CODE) {
577 if (context->expectedExitCode != context->exitCode) {
579 TestSuite_print("<EXIT CODE DON'T MATCH >\n");
582 TestSuite_print("<EXIT CODE MATCH >\n");
584 sprintf(str, "<EXIT CODE EXPECTED > (%3d)\n",
585 context->expectedExitCode);
586 TestSuite_print(str);
590 sprintf(str, "<EXIT CODE RETURNED > (%3d)\n",
592 TestSuite_print(str);
594 context->expectedExitCode = INVALID_EXIT_CODE;
598 setErrno(E_EXIT_CODE_DONT_MATCH);
606 * Terminate the test suite.
608 void TestSuite_terminate(TestSuite_t testSuite)
610 TestCaseContext_t context = testSuite->test_case_context;
612 /* cleanup the child_input_stream/output buffers. */
613 if (NULL != context->inputBuffer)
614 Buffer_free(context->inputBuffer);
616 if (NULL != context->outputBuffer)
617 Buffer_free(context->outputBuffer);
619 if (NULL != context->expectedOutputBuffer)
620 Buffer_free(context->expectedOutputBuffer);
622 /* close the file stream. */
623 if (NULL != testSuite->stream)
624 Stream_free(testSuite->stream);
633 void TestSuite_print(const char *str)
635 char *t = (char *) calloc(1, 20);
639 EnterCriticalSection(&cs);
640 printf("%s %s", t, str);
641 LeaveCriticalSection(&cs);
647 unsigned long WINAPI TestSuite_asyncReadChildOutput(void *param)
649 char str[1024] = { 0 };
650 char __buffer[1024] = { 0 };
654 TestCaseContext_t context = (TestCaseContext_t) param;
655 HANDLE hPipeRead = context->hOutputRead;
658 while (context->runThread) {
659 if (!ReadFile(hPipeRead, str, sizeof(str), &nBytesRead, NULL)
661 if (GetLastError() == ERROR_BROKEN_PIPE) {
665 context->threadExitCode = 1;
671 if (context->isOutputCheckingEnabled) {
672 if (!Buffer_empty(context->outputBuffer))
673 Buffer_clear(context->outputBuffer);
675 TestSuite_print(str);
678 Buffer_append(context->outputBuffer, str);
681 memset(str, 0, 1024);
682 memset(__buffer, 0, 1024);
686 context->threadExitCode = 0;
690 errno_t TestSuite_runAsyncTestCase(TestSuite_t testSuite)
693 s_ThreadEntry_t entry;
694 /* = (ThreadEntry_t)calloc(1,sizeof(s_ThreadEntry_t)); */
696 TestCaseContext_t context = testSuite->test_case_context;
697 memset(&entry, 0, sizeof(s_ThreadEntry_t));
698 entry.context = TestCaseContext_new();
700 Buffer_append(entry.context->inputBuffer, context->inputBuffer->data);
701 Buffer_append(entry.context->outputBuffer, context->outputBuffer->data);
702 Buffer_append(entry.context->expectedOutputBuffer,
703 context->expectedOutputBuffer->data);
704 Buffer_append(entry.context->commandLineBuffer,
705 context->commandLineBuffer->data);
706 entry.context->name = strdup(context->name);
707 entry.context->timeoutValue = context->timeoutValue;
708 entry.context->isOutputCheckingEnabled =
709 context->isOutputCheckingEnabled;
710 entry.context->isPostOutputCheckingEnabled =
711 context->isPostOutputCheckingEnabled;
712 entry.context->expectedExitCode = context->expectedExitCode;
713 entry.context->createConsole = context->createConsole;
714 entry.context->exitCodeCheckingEnabled =
715 context->exitCodeCheckingEnabled;
716 entry.context->hConsole = context->hConsole;
717 Buffer_clear(context->inputBuffer);
718 Buffer_clear(context->outputBuffer);
719 Buffer_clear(context->expectedOutputBuffer);
720 memset(&(entry.context->pi), 0, sizeof(PROCESS_INFORMATION));
721 entry.context->runThread = true;
724 CreateThread(NULL, 0, TestSuite_runSyncTestCase,
725 (LPVOID) entry.context, CREATE_SUSPENDED, &ThreadId);
726 entry.threadId = ThreadId;
727 ThreadDynarray_pushBack(testSuite->threads, &entry);
728 ResumeThread(entry.hThread);
735 unsigned long WINAPI TestSuite_runSyncTestCase(void *param)
737 STARTUPINFO si = { 0 };
738 SECURITY_ATTRIBUTES sa = { 0 };
739 DWORD dwWaitResult = 0;
740 DWORD dwExitCode = 0;
743 DWORD dwCreationMode = CREATE_NO_WINDOW;
744 char cmdLine[4098] = { 0 };
746 TestCaseContext_t context = (TestCaseContext_t) param;
747 context->started = true;
750 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
751 sa.lpSecurityDescriptor = NULL;
752 /* The pipe handes can be inherited by the child. */
753 sa.bInheritHandle = TRUE;
755 /* Create a write pipe handle for the child std output */
757 (&(context->hChildStdoutReadTmp), &(context->hChildStdOutWrite), &sa,
759 setErrno(E_CANNOT_CREATE_CHILD_STDOUT_READ_HANDLE);
764 * Create a duplicate of the output write handle for the std error
765 * write handle. This is necessary in case the child application closes
766 * one of its std output handles.
769 (GetCurrentProcess(), (context->hChildStdOutWrite),
770 GetCurrentProcess(), &(context->hChildStderr), 0, TRUE,
771 DUPLICATE_SAME_ACCESS)) {
772 setErrno(E_CANNOT_CREATE_CHILD_STDERR_READ_HANDLE);
776 /* Create a read pipe handle for the child std input */
778 (&(context->hChildStdInRead), &(context->hChildStdinWriteTmp), &sa,
780 setErrno(E_CANNOT_CREATE_CHILD_STDIN_WRITE_HANDLE);
785 /* Create new output read handle and the input write handle use by
786 * the parent process to communicate with his child. Set the Properties
787 * to FALSE. Otherwise, the child inherits the properties and, as a
788 * result, non-closeable handles to the pipes are created.
791 /* Read handle for read operations on the child std output. */
793 (GetCurrentProcess(), (context->hChildStdoutReadTmp),
794 GetCurrentProcess(), &(context->hOutputRead), 0, FALSE,
795 DUPLICATE_SAME_ACCESS)) {
796 setErrno(E_CANNOT_CREATE_STDOUT_READ_HANDLE);
801 /* Write handle for write operations on the child std input. */
803 (GetCurrentProcess(), (context->hChildStdinWriteTmp),
804 GetCurrentProcess(), &(context->hInputWrite), 0, FALSE,
805 DUPLICATE_SAME_ACCESS)) {
806 setErrno(E_CANNOT_CREATE_STDIN_WRITE_HANDLE);
811 /* Close inheritable copies of the handles you do not want to be inherited. */
812 if (!CloseHandle((context->hChildStdoutReadTmp))) {
813 setErrno(E_CANNOT_CLOSE_CHILD_STDIN_TEMPORY_HANDLE);
817 context->hChildStdoutReadTmp = NULL;
819 if (!CloseHandle((context->hChildStdinWriteTmp))) {
820 setErrno(E_CANNOT_CLOSE_CHILD_STDOUT_TEMPORY_HANDLE);
825 context->hChildStdinWriteTmp = NULL;
827 si.cb = sizeof(STARTUPINFO);
828 /* Set the child std handles. */
829 si.dwFlags = STARTF_USESTDHANDLES;
830 si.hStdOutput = context->hChildStdOutWrite;
831 si.hStdInput = context->hChildStdInRead;
832 si.hStdError = context->hChildStderr;
834 if (context->createConsole)
835 dwCreationMode = CREATE_NEW_CONSOLE;
837 if (!Buffer_empty(context->commandLineBuffer)) {
838 Buffer_chomp(context->commandLineBuffer);
839 sprintf(cmdLine, "%s %s", context->name,
840 context->commandLineBuffer->data);
842 strcpy(cmdLine, context->name);
845 /* Create the child process. */
847 (NULL, cmdLine, NULL, NULL, TRUE, dwCreationMode, NULL, NULL, &si,
849 setErrno(E_CANNOT_CREATE_CHILD_PROCESS);
853 if (!CloseHandle(context->pi.hThread)) {
854 setErrno(E_CANNOT_CLOSE_PROCESS_THREAD_HANDLE);
859 context->pi.hThread = NULL;
861 /* close unnessary pipe handles. */
862 if (!CloseHandle(context->hChildStdOutWrite)) {
863 setErrno(E_CANNOT_CLOSE_CHILD_STDOUT_HANDLE);
867 context->hChildStdOutWrite = NULL;
869 if (!CloseHandle(context->hChildStdInRead)) {
870 setErrno(E_CANNOT_CLOSE_CHILD_STDIN_HANDLE);
874 context->hChildStdInRead = NULL;
876 if (!CloseHandle(context->hChildStderr)) {
877 setErrno(E_CANNOT_CLOSE_CHILD_STDERR_HANDLE);
881 context->hChildStderr = NULL;
883 if (!Buffer_empty(context->inputBuffer)) {
885 (context->hInputWrite, context->inputBuffer->data,
886 context->inputBuffer->size, &nBytes, NULL)) {
887 setErrno(E_CANNOT_WRITE_ON_CHILD_STDIN);
893 CreateThread(&sa, 0, TestSuite_asyncReadChildOutput,
894 (LPVOID) context, 0, &ThreadId);
897 if (NULL == context->hThread) {
898 setErrno(E_CANNOT_CREATE_READ_CHILD_OUTPUT_THREAD);
904 WaitForSingleObject(context->pi.hProcess, context->timeoutValue);
906 if (WAIT_FAILED == dwWaitResult) {
907 TerminateProcess(context->pi.hProcess, 0);
908 context->pi.hProcess = NULL;
909 context->runThread = false;
911 if (WAIT_FAILED == WaitForSingleObject(context->hThread, INFINITE)) {
912 setErrno(E_WAIT_THREAD_FAILED);
916 if (!CloseHandle(context->hThread)) {
917 setErrno(E_CANNOT_CLOSE_THREAD_HANDLE);
921 context->hThread = NULL;
923 if (!CloseHandle(context->hOutputRead)) {
924 setErrno(E_CANNOT_CLOSE_READ_HANDLE);
928 context->hOutputRead = NULL;
930 if (!CloseHandle(context->hInputWrite)) {
931 setErrno(E_CANNOT_CLOSE_WRITE_HANDLE);
935 context->hInputWrite = NULL;
936 setErrno(E_WAIT_FAILURE);
940 if (WAIT_TIMEOUT == dwWaitResult) {
941 TerminateProcess(context->pi.hProcess, 0);
942 context->pi.hProcess = NULL;
943 context->runThread = false;
945 if (WAIT_FAILED == WaitForSingleObject(context->hThread, INFINITE)) {
946 setErrno(E_WAIT_THREAD_FAILED);
950 if (!CloseHandle(context->hThread)) {
951 setErrno(E_CANNOT_CLOSE_THREAD_HANDLE);
955 context->hThread = NULL;
957 if (!CloseHandle(context->hOutputRead)) {
958 setErrno(E_CANNOT_CLOSE_READ_HANDLE);
963 context->hOutputRead = NULL;
965 if (!CloseHandle(context->hInputWrite)) {
966 setErrno(E_CANNOT_CLOSE_WRITE_HANDLE);
970 context->hInputWrite = NULL;
971 setErrno(E_WAIT_TIMEOUT);
977 context->runThread = false;
979 if (WAIT_FAILED == WaitForSingleObject(context->hThread, INFINITE)) {
980 setErrno(E_WAIT_THREAD_FAILED);
984 if (!CloseHandle(context->hThread)) {
985 setErrno(E_CANNOT_CLOSE_THREAD_HANDLE);
989 context->hThread = NULL;
991 if (!CloseHandle(context->hOutputRead)) {
992 setErrno(E_CANNOT_CLOSE_READ_HANDLE);
996 context->hOutputRead = NULL;
998 if (!CloseHandle(context->hInputWrite)) {
999 setErrno(E_CANNOT_CLOSE_WRITE_HANDLE);
1003 context->hInputWrite = NULL;
1006 /* Get the child exit code before close it. */
1007 GetExitCodeProcess(context->pi.hProcess, &dwExitCode);
1009 context->exitCode = (int) dwExitCode;
1011 if (!CloseHandle(context->pi.hProcess)) {
1012 setErrno(E_CANNOT_CLOSE_PROCESS_HANDLE);
1016 context->runThread = true;
1018 if (TestSuite_iSPostOutputCheckingEnabled(context)) {
1019 if (context->expectedOutputBuffer->size != 0
1020 || context->outputBuffer->size != 0) {
1021 Buffer_chomp(context->outputBuffer);
1022 Buffer_chomp(context->expectedOutputBuffer);
1024 if (context->outputBuffer->size !=
1025 context->expectedOutputBuffer->size
1026 || strcmp(context->outputBuffer->data,
1027 context->expectedOutputBuffer->data)) {
1028 setErrno(E_OUTPUT_DONT_MATCH);
1033 if (TestSuite_iSExitCodeCheckingEnabled(context)) {
1034 if (context->expectedExitCode != INVALID_EXIT_CODE) {
1035 if (context->expectedExitCode != context->exitCode) {
1036 setErrno(E_EXIT_CODE_DONT_MATCH);
1041 context->pi.hProcess = NULL;
1045 bool TestSuite_iSPostOutputCheckingEnabled(TestCaseContext_t context)
1047 if (!context->isPostOutputCheckingEnabled
1048 && context->isOutputCheckingEnabled) {
1055 bool TestSuite_iSExitCodeCheckingEnabled(TestCaseContext_t context)
1057 return context->exitCodeCheckingEnabled;
1060 errno_t TestSuite_changeDir(TestSuite_t testSuite)
1062 char *line = testSuite->stream->line + 5;
1063 size_t size = strlen(line);
1065 while ((line[size - 1] == '\n') || (line[size - 1] == '\r')) {
1066 line[size - 1] = '\0';
1072 if (!SetCurrentDirectory(line)) {
1073 setErrno(E_CHANGE_DIRECTORY_FAILED);
1074 return E_CHANGE_DIRECTORY_FAILED;
1077 Stream_printLine(testSuite->stream, change_directory_line_type);