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[])
54 TestSuite_print("Run the test case from the console.\n");
56 ptr->stream->file = stdin;
61 if(E_SUCCESS != Stream_isValidFile(argv[1]))
64 printf("\n\n Test runner : %s\n\n",argv[1]);
66 if(E_SUCCESS != Stream_openFile(ptr->stream,argv[1]))
73 setErrno(E_BAD_USAGE);
80 * Launch the test suite.
82 void TestSuite_run(TestSuite_t testSuite)
84 Stream_t stream = testSuite->stream;
86 /* Handle all lines in the testsuite file (or from stdin) */
87 while((Stream_getLine(stream) != -1) && (E_SUCCESS == getErrno()))
89 /* Don't process blank lines. */
90 if (Stream_lineIsBlank(stream))
93 /* Check if the current text line contains a invalid token. */
94 if(Stream_lineContainsInvalidToken(stream))
97 /* Check if the text line contains a meta command. */
98 if(Stream_lineIsMetaCommand(stream)){
99 /* Check if the current text line contains a unknown meta command. */
100 if(Stream_lineIsUnknwnMetaCommand(stream))
103 /* Check the meta command validity.*/
104 if(Stream_lineIsInvalidMetaCommand(stream))
107 /* We have a valid meta command, process it */
108 if(E_SUCCESS != TestSuite_processMetaCommand(testSuite))
114 /* Handle the comment. */
115 if(Stream_lineIsComment(stream)){
116 Stream_printLine(testSuite->stream,comment_line_type);
120 /* Handle expected child output. */
121 if(Stream_lineIsExpectedChildOutput(stream)){
122 if(E_SUCCESS != TestSuite_processExpectedChildOutput(testSuite))
128 /* Handle expected child input. */
129 if(Stream_lineIsChildInput(stream)){
130 if(E_SUCCESS != TestSuite_processChildInput(testSuite))
136 if(Stream_lineIsChangeDir(stream)){
137 if(E_SUCCESS != TestSuite_changeDir(testSuite))
143 /* Handle synchrone synchrone test case. */
144 if(Stream_lineIsSyncTestCase(stream)){
145 TestCaseContext_setName(testSuite->test_case_context,stream->line + 2);
147 TestSuite_runSyncTestCase(testSuite->test_case_context);
150 if(TestSuite_iSPostOutputCheckingEnabled(testSuite->test_case_context)){
151 TestSuite_checkChildOutput(testSuite->test_case_context);
154 if(TestSuite_iSExitCodeCheckingEnabled(testSuite->test_case_context)){
155 if(E_SUCCESS != TestSuite_checkChildExitCode(testSuite->test_case_context))
160 if(E_SUCCESS != getErrno())
163 /* Handle asynchrone synchrone test case. */
164 else if(Stream_lineIsAsyncTestCase(stream))
166 TestCaseContext_setName(testSuite->test_case_context,stream->line + 2);
168 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);
183 * Meta command processing.
185 errno_t TestSuite_processMetaCommand(TestSuite_t testSuite)
187 Stream_t stream = testSuite->stream;
189 if(!strncmp("set timeout ",stream->line + 2,strlen("set timeout ")))
191 TestSuite_setTimeout(testSuite);
193 else if(!strncmp("command line ",stream->line + 2,strlen("command line")))
195 TestSuite_setCommandLine(testSuite);
197 else if(!strncmp("enable output checking",stream->line + 2,strlen("enable output checking")))
199 TestSuite_enableOutputChecking(testSuite);
201 else if(!strncmp("disable output checking",stream->line + 2,strlen("disable output checking")))
203 TestSuite_disableOutputChecking(testSuite);
205 else if(!strncmp("enable post output checking",stream->line + 2,strlen("enable post output checking")))
207 TestSuite_enablePostOutputChecking(testSuite);
209 else if(!strncmp("disable post output checking",stream->line + 2,strlen("disable post output checking")))
211 TestSuite_disablePostOutputChecking(testSuite);
213 else if(!strncmp("expect exit code ",stream->line + 2,strlen("expect exit code ")))
215 TestSuite_setExpectedExitCode(testSuite);
217 else if(!strncmp("export ",stream->line + 2,strlen("export ")))
219 TestSuite_export(testSuite);
221 else if(!strncmp("unset ",stream->line + 2,strlen("unset ")))
223 TestSuite_unset(testSuite);
225 else if(!strncmp("create console",stream->line + 2,strlen("create console")))
227 TestSuite_createConsole(testSuite);
229 else if(!strncmp("create no console",stream->line + 2,strlen("create no console")))
231 TestSuite_createNoConsole(testSuite);
233 else if(!strncmp("enable exit code checking",stream->line + 2,strlen("enable exit code checking")))
235 TestSuite_enableExitCodeChecking(testSuite);
237 else if(!strncmp("disable exit code checking",stream->line + 2,strlen("disable exit code checking")))
239 TestSuite_disableExitCodeChecking(testSuite);
252 * Set the timeout of the test case context of the
255 void TestSuite_setTimeout(TestSuite_t testSuite)
258 int timeout = atoi(testSuite->stream->line + 2 + strlen("set timeout "));
259 TestCaseContext_setTimeout(testSuite->test_case_context,timeout);
263 * Enable output checking for the current test case context.
265 void TestSuite_enableOutputChecking(TestSuite_t testSuite)
267 TestCaseContext_enableOutputChecking(testSuite->test_case_context);
270 void TestSuite_setCommandLine(TestSuite_t testSuite)
272 TestCaseContext_setCommandLine(testSuite->test_case_context,testSuite->stream->line + 2 + strlen("command line "));
276 * Disable output checking for the current test case context.
278 void TestSuite_disableOutputChecking(TestSuite_t testSuite)
280 TestCaseContext_disableOutputChecking(testSuite->test_case_context);
284 * Enable post output checking for the current test case context.
286 void TestSuite_enablePostOutputChecking(TestSuite_t testSuite)
288 TestCaseContext_enable_post_output_checking(testSuite->test_case_context);
291 void TestSuite_createConsole(TestSuite_t testSuite)
293 TestCaseContext_createConsole(testSuite->test_case_context);
296 void TestSuite_createNoConsole(TestSuite_t testSuite)
298 TestCaseContext_createNoConsole(testSuite->test_case_context);
302 * Disable post output checking for the current test case context.
304 void TestSuite_disablePostOutputChecking(TestSuite_t testSuite)
306 TestCaseContext_disablePostOutputChecking(testSuite->test_case_context);
310 * Set the expected exit code of the current test case context of the test suite.
312 void TestSuite_setExpectedExitCode(TestSuite_t testSuite)
314 int expectedExitCode = atoi(testSuite->stream->line + 2 + strlen("expect exit code "));
315 TestCaseContext_setExpectedExitCode(testSuite->test_case_context,expectedExitCode);
318 void TestSuite_enableExitCodeChecking(TestSuite_t testSuite)
320 TestCaseContext_enableExitCodeChecking(testSuite->test_case_context);
323 void TestSuite_disableExitCodeChecking(TestSuite_t testSuite)
325 TestCaseContext_disableExitCodeChecking(testSuite->test_case_context);
330 * Export a variable in the environment of the current test_runner.exe process.
332 errno_t TestSuite_export(TestSuite_t testSuite)
337 char __buffer[50] = {0};
338 char* line = testSuite->stream->line + strlen("export ");
340 line[strlen(line) -1] = '\0';
342 ptr = strchr(line,' ');
344 ptr = strchr(line,'=');
345 strncpy(__buffer,pos,ptr - pos);
346 if(!SetEnvironmentVariable(__buffer,++ptr))
348 setErrno(E_EXPORT_FAILED);
349 Stream_printLine(testSuite->stream,export_failed_line_type);
357 errno_t TestSuite_unset(TestSuite_t testSuite)
359 char line[128] = {0};
361 strcpy(line,testSuite->stream->line +2);
362 ptr = strchr(line,' ');
363 line[strlen(line) -1] = '\0';
365 if(!SetEnvironmentVariable(++ptr,NULL))
368 setErrno(E_UNSET_FAILED);
369 Stream_printLine(testSuite->stream,unset_failed_line_type);
377 * Expected child output processing.
379 errno_t TestSuite_processExpectedChildOutput(TestSuite_t testSuite)
381 /* TODO : logic error*/
382 if(!TestCaseContext_isOutputCheckingEnabled(testSuite->test_case_context))
386 TestCaseContext_appendExpectedOutput(testSuite->test_case_context,testSuite->stream->line + 2);
392 * Child input processing.
394 errno_t TestSuite_processChildInput(TestSuite_t testSuite)
397 TestCaseContext_appendChildInput(testSuite->test_case_context,testSuite->stream->line + 2);
403 * Free the s_TestSuite pointed to by ptr.
405 void TestSuite_free(TestSuite_t testSuite)
412 bool last_async_process_error = false;
414 errno_t e = getErrno();
416 if(NULL == testSuite)
419 count = ThreadDynarray_getCount(testSuite->threads);
421 /* Wait for all asynchrone process */
422 if(NULL != testSuite->threads && count)
426 steel_running = false;
428 for(i = 0;i < count ; i++)
430 entry = ThreadDynarray_at(testSuite->threads,i);
432 GetExitCodeThread(entry->hThread,&ExitCode);
434 if(STILL_ACTIVE == ExitCode)
437 steel_running = true;
445 for(i = 0;i <count;i++)
447 entry = ThreadDynarray_at(testSuite->threads,i);
449 if(entry->context->pi.hProcess)
451 dwWaitResult=WaitForSingleObject(entry->hThread,INFINITE);
453 if((WAIT_FAILED == dwWaitResult))
454 TerminateThread(entry->hThread,0);
456 CloseHandle(entry->hThread);
459 /*if(((E_SUCCESS == e) || (E_EXIT_CODE_DONT_MATCH == e) || (E_OUTPUT_DONT_MATCH == e)) && !last_async_process_error)
461 /* Child output and exit code checking */
462 if(TestSuite_iSPostOutputCheckingEnabled(entry->context))
464 if(E_SUCCESS != TestSuite_checkChildOutput(entry->context))
465 last_async_process_error = true;
468 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;
499 if (context->expectedOutputBuffer->size==0 && context->outputBuffer->size==0)
502 Buffer_chomp(context->outputBuffer);
503 Buffer_chomp(context->expectedOutputBuffer);
506 if (context->outputBuffer->size != context->expectedOutputBuffer->size || strcmp(context->outputBuffer->data, context->expectedOutputBuffer->data))
508 strcpy(str,"<OUTPUT NOT MATCH > \n");
509 TestSuite_print(str);
515 strcpy(str,"<OUTPUT MATCH > \n");
516 TestSuite_print(str);
523 if(context->expectedOutputBuffer->size)
525 sprintf(str,"<EXPECTED > SIZE (%4d) DATA (%s)\n",context->expectedOutputBuffer->size,context->expectedOutputBuffer->data);
526 TestSuite_print(str);
530 scanf(str,"<EXPECTED > SIZE (%4d) DATA (%s)\n",context->expectedOutputBuffer->size,"empty");
531 TestSuite_print(str);
536 if(context->outputBuffer->size)
538 sprintf(str,"<RECEIVED > SIZE (%4d) DATA (%s)\n",context->outputBuffer->size,context->outputBuffer->data);
539 TestSuite_print(str);
543 sprintf(str,"<RECEIVED > SIZE (%4d) DATA (%s)\n",context->outputBuffer->size,"empty");
544 TestSuite_print(str);
547 Buffer_clear(context->expectedOutputBuffer);
548 Buffer_clear(context->outputBuffer);
552 setErrno(E_OUTPUT_DONT_MATCH);
560 * Check the child process exit code.
562 errno_t TestSuite_checkChildExitCode(TestCaseContext_t context)
564 bool __success = false;
567 sprintf(str,"<TEST CASE TERMINATED > %s %3ld\n",context->name,context->exitCode);
568 TestSuite_print(str);
572 /* if a expected exit code was signaled, compare it with the real. */
573 if(context->expectedExitCode != INVALID_EXIT_CODE)
575 if(context->expectedExitCode != context->exitCode )
578 TestSuite_print("<EXIT CODE DON'T MATCH >\n");
583 TestSuite_print("<EXIT CODE MATCH >\n");
585 sprintf(str,"<EXIT CODE EXPECTED > (%3d)\n",context->expectedExitCode);
586 TestSuite_print(str);
590 sprintf(str,"<EXIT CODE RETURNED > (%3d)\n",context->exitCode);
591 TestSuite_print(str);
593 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)
660 if (!ReadFile(hPipeRead,str,sizeof(str),&nBytesRead,NULL) || !nBytesRead){
661 if (GetLastError() == ERROR_BROKEN_PIPE){
666 context->threadExitCode = 1;
672 if(context->isOutputCheckingEnabled){
673 if(!Buffer_empty(context->outputBuffer))
674 Buffer_clear(context->outputBuffer);
676 TestSuite_print(str);
679 Buffer_append(context->outputBuffer,str);
683 memset(__buffer,0,1024);
687 context->threadExitCode = 0;
691 errno_t TestSuite_runAsyncTestCase(TestSuite_t testSuite)
694 s_ThreadEntry_t entry;
695 /* = (ThreadEntry_t)calloc(1,sizeof(s_ThreadEntry_t));*/
697 TestCaseContext_t context = testSuite->test_case_context;
698 memset(&entry,0,sizeof(s_ThreadEntry_t));
699 entry.context = TestCaseContext_new();
701 Buffer_append(entry.context->inputBuffer,context->inputBuffer->data);
702 Buffer_append(entry.context->outputBuffer,context->outputBuffer->data);
703 Buffer_append(entry.context->expectedOutputBuffer,context->expectedOutputBuffer->data);
704 Buffer_append(entry.context->commandLineBuffer,context->commandLineBuffer->data);
705 entry.context->name = strdup(context->name);
706 entry.context->timeoutValue = context->timeoutValue;
707 entry.context->isOutputCheckingEnabled = context->isOutputCheckingEnabled;
708 entry.context->isPostOutputCheckingEnabled = context->isPostOutputCheckingEnabled;
709 entry.context->expectedExitCode = context->expectedExitCode;
710 entry.context->createConsole = context->createConsole;
711 entry.context->exitCodeCheckingEnabled = context->exitCodeCheckingEnabled;
712 entry.context->hConsole = context->hConsole;
713 Buffer_clear(context->inputBuffer);
714 Buffer_clear(context->outputBuffer);
715 Buffer_clear(context->expectedOutputBuffer);
716 memset(&(entry.context->pi),0,sizeof(PROCESS_INFORMATION));
717 entry.context->runThread = true;
719 entry.hThread = CreateThread(NULL,0,TestSuite_runSyncTestCase,(LPVOID)entry.context,CREATE_SUSPENDED,&ThreadId);
720 entry.threadId = ThreadId;
721 ThreadDynarray_pushBack(testSuite->threads,&entry);
722 ResumeThread(entry.hThread);
729 unsigned long WINAPI TestSuite_runSyncTestCase( void* param)
731 STARTUPINFO si = {0};
732 SECURITY_ATTRIBUTES sa = {0};
733 DWORD dwWaitResult = 0;
734 DWORD dwExitCode = 0;
737 DWORD dwCreationMode = CREATE_NO_WINDOW;
738 char cmdLine[4098] = {0};
740 TestCaseContext_t context = (TestCaseContext_t)param;
741 context->started = true;
744 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
745 sa.lpSecurityDescriptor = NULL;
746 /* The pipe handes can be inherited by the child. */
747 sa.bInheritHandle = TRUE;
749 /* Create a write pipe handle for the child std output */
750 if(!CreatePipe(&(context->hChildStdoutReadTmp),&(context->hChildStdOutWrite),&sa,0))
752 setErrno(E_CANNOT_CREATE_CHILD_STDOUT_READ_HANDLE);
757 * Create a duplicate of the output write handle for the std error
758 * write handle. This is necessary in case the child application closes
759 * one of its std output handles.
761 if(!DuplicateHandle(GetCurrentProcess(),(context->hChildStdOutWrite),GetCurrentProcess(),&(context->hChildStderr),0,TRUE,DUPLICATE_SAME_ACCESS))
763 setErrno(E_CANNOT_CREATE_CHILD_STDERR_READ_HANDLE);
767 /* Create a read pipe handle for the child std input */
768 if(!CreatePipe(&(context->hChildStdInRead),&(context->hChildStdinWriteTmp),&sa,0))
770 setErrno(E_CANNOT_CREATE_CHILD_STDIN_WRITE_HANDLE);
775 /* Create new output read handle and the input write handle use by
776 * the parent process to communicate with his child. Set the Properties
777 * to FALSE. Otherwise, the child inherits the properties and, as a
778 * result, non-closeable handles to the pipes are created.
781 /* Read handle for read operations on the child std output. */
782 if(!DuplicateHandle(GetCurrentProcess(),(context->hChildStdoutReadTmp),GetCurrentProcess(),&(context->hOutputRead),0,FALSE, DUPLICATE_SAME_ACCESS))
784 setErrno(E_CANNOT_CREATE_STDOUT_READ_HANDLE);
789 /* Write handle for write operations on the child std input. */
790 if(!DuplicateHandle(GetCurrentProcess(),(context->hChildStdinWriteTmp),GetCurrentProcess(),&(context->hInputWrite), 0,FALSE,DUPLICATE_SAME_ACCESS))
792 setErrno(E_CANNOT_CREATE_STDIN_WRITE_HANDLE);
797 /* Close inheritable copies of the handles you do not want to be inherited. */
798 if(!CloseHandle((context->hChildStdoutReadTmp)))
800 setErrno(E_CANNOT_CLOSE_CHILD_STDIN_TEMPORY_HANDLE);
804 context->hChildStdoutReadTmp = NULL;
806 if(!CloseHandle((context->hChildStdinWriteTmp)))
808 setErrno(E_CANNOT_CLOSE_CHILD_STDOUT_TEMPORY_HANDLE);
813 context->hChildStdinWriteTmp = NULL;
815 si.cb = sizeof(STARTUPINFO);
816 /* Set the child std handles. */
817 si.dwFlags = STARTF_USESTDHANDLES;
818 si.hStdOutput = context->hChildStdOutWrite;
819 si.hStdInput = context->hChildStdInRead;
820 si.hStdError = context->hChildStderr;
822 if(context->createConsole)
823 dwCreationMode = CREATE_NEW_CONSOLE;
825 if(!Buffer_empty(context->commandLineBuffer)){
826 Buffer_chomp(context->commandLineBuffer);
827 sprintf(cmdLine,"%s %s",context->name,context->commandLineBuffer->data);
830 strcpy(cmdLine,context->name);
833 /* Create the child process. */
834 if(!CreateProcess(NULL,cmdLine,NULL,NULL,TRUE,dwCreationMode,NULL,NULL,&si,&(context->pi))){
835 setErrno(E_CANNOT_CREATE_CHILD_PROCESS);
839 if(!CloseHandle(context->pi.hThread)){
840 setErrno(E_CANNOT_CLOSE_PROCESS_THREAD_HANDLE);
845 context->pi.hThread = NULL;
847 /* close unnessary pipe handles. */
848 if(!CloseHandle(context->hChildStdOutWrite)){
849 setErrno(E_CANNOT_CLOSE_CHILD_STDOUT_HANDLE);
853 context->hChildStdOutWrite = NULL;
855 if(!CloseHandle(context->hChildStdInRead)){
856 setErrno(E_CANNOT_CLOSE_CHILD_STDIN_HANDLE);
860 context->hChildStdInRead = NULL;
862 if(!CloseHandle(context->hChildStderr)){
863 setErrno(E_CANNOT_CLOSE_CHILD_STDERR_HANDLE);
867 context->hChildStderr = NULL;
869 if(!Buffer_empty(context->inputBuffer)){
870 if(!WriteFile(context->hInputWrite,context->inputBuffer->data,context->inputBuffer->size,&nBytes,NULL)){
871 setErrno(E_CANNOT_WRITE_ON_CHILD_STDIN);
876 context->hThread = CreateThread(&sa,0,TestSuite_asyncReadChildOutput,(LPVOID)context,0,&ThreadId);
879 if(NULL == context->hThread){
880 setErrno(E_CANNOT_CREATE_READ_CHILD_OUTPUT_THREAD);
885 dwWaitResult = WaitForSingleObject(context->pi.hProcess,context->timeoutValue);
887 if(WAIT_FAILED == dwWaitResult)
889 TerminateProcess(context->pi.hProcess,0);
890 context->pi.hProcess = NULL;
891 context->runThread = false;
893 if(WAIT_FAILED == WaitForSingleObject(context->hThread,INFINITE)){
894 setErrno(E_WAIT_THREAD_FAILED);
898 if(!CloseHandle(context->hThread)){
899 setErrno(E_CANNOT_CLOSE_THREAD_HANDLE);
903 context->hThread = NULL;
905 if(!CloseHandle(context->hOutputRead)){
906 setErrno(E_CANNOT_CLOSE_READ_HANDLE);
910 context->hOutputRead = NULL;
912 if(!CloseHandle(context->hInputWrite)){
913 setErrno(E_CANNOT_CLOSE_WRITE_HANDLE);
917 context->hInputWrite = NULL;
918 setErrno(E_WAIT_FAILURE);
922 if(WAIT_TIMEOUT == dwWaitResult)
924 TerminateProcess(context->pi.hProcess,0);
925 context->pi.hProcess = NULL;
926 context->runThread = false;
928 if(WAIT_FAILED == WaitForSingleObject(context->hThread,INFINITE)){
929 setErrno(E_WAIT_THREAD_FAILED);
933 if(!CloseHandle(context->hThread)){
934 setErrno(E_CANNOT_CLOSE_THREAD_HANDLE);
938 context->hThread = NULL;
940 if(!CloseHandle(context->hOutputRead)){
941 setErrno(E_CANNOT_CLOSE_READ_HANDLE);
946 context->hOutputRead = NULL;
948 if(!CloseHandle(context->hInputWrite)){
949 setErrno(E_CANNOT_CLOSE_WRITE_HANDLE);
953 context->hInputWrite = NULL;
954 setErrno(E_WAIT_TIMEOUT);
960 context->runThread = false;
962 if(WAIT_FAILED == WaitForSingleObject(context->hThread,INFINITE)){
963 setErrno(E_WAIT_THREAD_FAILED);
967 if(!CloseHandle(context->hThread)){
968 setErrno(E_CANNOT_CLOSE_THREAD_HANDLE);
972 context->hThread = NULL;
974 if(!CloseHandle(context->hOutputRead)){
975 setErrno(E_CANNOT_CLOSE_READ_HANDLE);
979 context->hOutputRead = NULL;
981 if(!CloseHandle(context->hInputWrite)){
982 setErrno(E_CANNOT_CLOSE_WRITE_HANDLE);
986 context->hInputWrite = NULL;
989 /* Get the child exit code before close it. */
990 GetExitCodeProcess(context->pi.hProcess,&dwExitCode);
992 context->exitCode = (int)dwExitCode;
994 if(!CloseHandle(context->pi.hProcess)){
995 setErrno(E_CANNOT_CLOSE_PROCESS_HANDLE);
999 context->runThread = true;
1001 if(TestSuite_iSPostOutputCheckingEnabled(context)){
1002 if (context->expectedOutputBuffer->size !=0 || context->outputBuffer->size !=0){
1003 Buffer_chomp(context->outputBuffer);
1004 Buffer_chomp(context->expectedOutputBuffer);
1006 if (context->outputBuffer->size != context->expectedOutputBuffer->size || strcmp(context->outputBuffer->data, context->expectedOutputBuffer->data)){
1007 setErrno(E_OUTPUT_DONT_MATCH);
1012 if(TestSuite_iSExitCodeCheckingEnabled(context)){
1013 if(context->expectedExitCode != INVALID_EXIT_CODE){
1014 if(context->expectedExitCode != context->exitCode ){
1015 setErrno(E_EXIT_CODE_DONT_MATCH);
1020 context->pi.hProcess = NULL;
1024 bool TestSuite_iSPostOutputCheckingEnabled(TestCaseContext_t context)
1026 if(!context->isPostOutputCheckingEnabled && context->isOutputCheckingEnabled){
1033 bool TestSuite_iSExitCodeCheckingEnabled(TestCaseContext_t context)
1035 return context->exitCodeCheckingEnabled;
1038 errno_t TestSuite_changeDir(TestSuite_t testSuite)
1040 char* line = testSuite->stream->line + 5;
1041 size_t size = strlen(line);
1043 while ((line[size-1] == '\n') || (line[size-1] == '\r')){
1044 line[size-1] = '\0';
1050 if(!SetCurrentDirectory(line)){
1051 setErrno(E_CHANGE_DIRECTORY_FAILED);
1052 return E_CHANGE_DIRECTORY_FAILED;
1055 Stream_printLine(testSuite->stream,change_directory_line_type);