Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Slight clarification of variable names
[simgrid.git] / win32_test_app / src / TTestSuite.c
1 #include <TTestSuite.h>
2
3
4 /*
5  * Create a new s_TestSuite an returns a pointer to self.
6  */
7 TestSuite_t TestSuite_new(void)
8 {
9         TestSuite_t testSuite = calloc(1,sizeof(s_TestSuite_t));
10         
11         if(NULL == testSuite){
12                 setErrno(E_TEST_SUITE_ALLOCATION_FAILED);
13                 TestSuite_free(testSuite);
14         return NULL;
15         }
16         
17         testSuite->stream = Stream_new();
18         
19         if(NULL == testSuite->stream){
20                 TestSuite_free(testSuite);
21                 return NULL;
22         }
23         
24         testSuite->test_case_context = TestCaseContext_new();
25         
26         if(NULL == testSuite->test_case_context){
27                 TestSuite_free(testSuite);
28                 return NULL;
29         }
30
31     testSuite->test_case_context->hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
32
33     testSuite->threads = ThreadDynarray_new(15);
34
35     if(NULL == testSuite->threads){
36         TestSuite_free(testSuite);
37         return NULL;
38     }
39
40         testSuite->successCount = 0;
41         testSuite->failureCount = 0;
42         
43         return testSuite;
44 }
45
46 /*
47  * Initialize the s_TestSuite structure.
48  */
49 errno_t TestSuite_initialize(TestSuite_t ptr,int argc,char *argv[])
50 {
51         switch(argc)
52         {
53                 case 1:
54                 TestSuite_print("Run the test case from the console.\n"); 
55                 
56                 ptr->stream->file = stdin;
57                 return E_SUCCESS;
58
59                 case 2:
60                         
61                 if(E_SUCCESS != Stream_isValidFile(argv[1]))
62                         return getErrno();
63
64                 printf("\n\n Test runner : %s\n\n",argv[1]);
65                 
66                 if(E_SUCCESS != Stream_openFile(ptr->stream,argv[1]))
67                         return getErrno();
68                 
69                 return E_SUCCESS;
70                         
71                 default:
72                 {
73                         setErrno(E_BAD_USAGE);
74                         return getErrno();
75                 }
76         }       
77 }
78
79 /* 
80  * Launch the test suite. 
81  */
82 void TestSuite_run(TestSuite_t testSuite)
83 {
84         Stream_t stream = testSuite->stream;
85
86         /* Handle all lines in the testsuite file (or from stdin) */
87         while((Stream_getLine(stream) != -1) && (E_SUCCESS  == getErrno()))
88         {
89                 /* Don't process blank lines. */
90                 if (Stream_lineIsBlank(stream))
91                         continue;
92                 
93                 /* Check if the current text line contains a invalid token. */
94                 if(Stream_lineContainsInvalidToken(stream))
95                         return;
96
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))
101                 return;
102
103                         /* Check the meta command validity.*/
104             if(Stream_lineIsInvalidMetaCommand(stream))
105                 return;
106                                 
107                         /* We have a valid meta command, process it */
108                         if(E_SUCCESS != TestSuite_processMetaCommand(testSuite))
109                                 return;
110                                 
111                         continue;
112                 }
113
114                 /* Handle the comment. */
115                 if(Stream_lineIsComment(stream)){
116                         Stream_printLine(testSuite->stream,comment_line_type);
117                         continue;
118                 }       
119                 
120                 /* Handle expected child output. */
121                 if(Stream_lineIsExpectedChildOutput(stream)){
122                         if(E_SUCCESS != TestSuite_processExpectedChildOutput(testSuite))
123                                 return;
124                 
125                         continue;
126                 }
127
128                 /* Handle expected child input. */
129                 if(Stream_lineIsChildInput(stream)){
130                         if(E_SUCCESS != TestSuite_processChildInput(testSuite))
131                                 return;
132                         
133                         continue;
134                 }
135
136         if(Stream_lineIsChangeDir(stream)){
137             if(E_SUCCESS != TestSuite_changeDir(testSuite))
138                 return;
139
140             continue;
141         }
142                 
143                 /* Handle synchrone synchrone test case. */
144                 if(Stream_lineIsSyncTestCase(stream)){
145                         TestCaseContext_setName(testSuite->test_case_context,stream->line + 2);
146                         
147                         TestSuite_runSyncTestCase(testSuite->test_case_context);
148
149
150             if(TestSuite_iSPostOutputCheckingEnabled(testSuite->test_case_context)){
151                             TestSuite_checkChildOutput(testSuite->test_case_context);
152             }
153
154                     if(TestSuite_iSExitCodeCheckingEnabled(testSuite->test_case_context)){
155                         if(E_SUCCESS != TestSuite_checkChildExitCode(testSuite->test_case_context))
156                     return;
157             }
158
159
160             if(E_SUCCESS != getErrno())
161                 return;
162                 }
163         /* Handle asynchrone synchrone test case. */
164                 else if(Stream_lineIsAsyncTestCase(stream))
165                 {
166                         TestCaseContext_setName(testSuite->test_case_context,stream->line + 2);
167                         
168                         if(E_SUCCESS != TestSuite_runAsyncTestCase(testSuite))
169                                 return;
170                 }
171                 else
172                 {
173                         ASSERT(false);
174                 }
175
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);
180         }
181 }
182 /* 
183  * Meta command processing.
184  */
185 errno_t TestSuite_processMetaCommand(TestSuite_t testSuite)
186 {
187     Stream_t stream = testSuite->stream;
188     
189         if(!strncmp("set timeout ",stream->line + 2,strlen("set timeout ")))
190         {
191                 TestSuite_setTimeout(testSuite);        
192         }
193     else if(!strncmp("command line ",stream->line + 2,strlen("command line")))
194         {
195                 TestSuite_setCommandLine(testSuite);
196         }
197         else if(!strncmp("enable output checking",stream->line + 2,strlen("enable output checking")))
198         {
199                 TestSuite_enableOutputChecking(testSuite);
200         }
201         else if(!strncmp("disable output checking",stream->line + 2,strlen("disable output checking")))
202         {
203                 TestSuite_disableOutputChecking(testSuite);
204         }       
205         else if(!strncmp("enable post output checking",stream->line + 2,strlen("enable post output checking")))
206         {
207                 TestSuite_enablePostOutputChecking(testSuite);  
208         }       
209         else if(!strncmp("disable post output checking",stream->line + 2,strlen("disable post output checking")))
210         {
211                 TestSuite_disablePostOutputChecking(testSuite);
212         }       
213         else if(!strncmp("expect exit code ",stream->line + 2,strlen("expect exit code ")))
214         {
215                 TestSuite_setExpectedExitCode(testSuite);
216         }
217         else if(!strncmp("export ",stream->line + 2,strlen("export ")))
218         {
219                 TestSuite_export(testSuite);
220         }
221         else if(!strncmp("unset ",stream->line + 2,strlen("unset ")))
222         {
223                 TestSuite_unset(testSuite);
224         }
225     else if(!strncmp("create console",stream->line + 2,strlen("create console")))
226         {
227                 TestSuite_createConsole(testSuite);
228         }
229         else if(!strncmp("create no console",stream->line + 2,strlen("create no console")))
230         {
231                 TestSuite_createNoConsole(testSuite);
232         }
233     else if(!strncmp("enable exit code checking",stream->line + 2,strlen("enable exit code checking")))
234         {
235                 TestSuite_enableExitCodeChecking(testSuite);
236         }
237     else if(!strncmp("disable exit code checking",stream->line + 2,strlen("disable exit code checking")))
238         {
239                 TestSuite_disableExitCodeChecking(testSuite);
240         }
241         else
242         {
243         /* TODO */
244                 ASSERT(false);
245         }       
246         
247         return E_SUCCESS;
248                 
249 }
250
251 /* 
252  * Set the timeout of the test case context of the
253  * test suite.
254  */
255 void TestSuite_setTimeout(TestSuite_t testSuite)
256 {
257         
258         int timeout = atoi(testSuite->stream->line + 2 + strlen("set timeout "));
259         TestCaseContext_setTimeout(testSuite->test_case_context,timeout);       
260 }
261
262 /*
263  * Enable output checking for the current test case context.
264  */
265 void TestSuite_enableOutputChecking(TestSuite_t testSuite)
266 {
267         TestCaseContext_enableOutputChecking(testSuite->test_case_context);
268 }
269
270 void TestSuite_setCommandLine(TestSuite_t testSuite)
271 {
272     TestCaseContext_setCommandLine(testSuite->test_case_context,testSuite->stream->line + 2 + strlen("command line "));
273 }
274
275 /*
276  * Disable output checking for the current test case context.
277  */
278 void TestSuite_disableOutputChecking(TestSuite_t testSuite)
279 {
280         TestCaseContext_disableOutputChecking(testSuite->test_case_context);
281 }
282
283 /*
284  * Enable post output checking for the current test case context.
285  */
286 void TestSuite_enablePostOutputChecking(TestSuite_t testSuite)
287 {
288         TestCaseContext_enable_post_output_checking(testSuite->test_case_context);
289 }
290
291 void TestSuite_createConsole(TestSuite_t testSuite)
292 {
293     TestCaseContext_createConsole(testSuite->test_case_context);
294 }
295
296 void TestSuite_createNoConsole(TestSuite_t testSuite)
297 {
298     TestCaseContext_createNoConsole(testSuite->test_case_context);
299 }
300
301 /*
302  * Disable post output checking for the current test case context.
303  */
304 void TestSuite_disablePostOutputChecking(TestSuite_t testSuite)
305 {
306         TestCaseContext_disablePostOutputChecking(testSuite->test_case_context);
307 }
308
309 /*
310  * Set the expected exit code of the current test case context of the test suite.
311  */
312 void TestSuite_setExpectedExitCode(TestSuite_t testSuite)
313 {
314         int expectedExitCode = atoi(testSuite->stream->line + 2 + strlen("expect exit code "));
315         TestCaseContext_setExpectedExitCode(testSuite->test_case_context,expectedExitCode);
316 }
317
318 void TestSuite_enableExitCodeChecking(TestSuite_t testSuite)
319 {
320     TestCaseContext_enableExitCodeChecking(testSuite->test_case_context);
321 }
322
323 void TestSuite_disableExitCodeChecking(TestSuite_t testSuite)
324 {
325     TestCaseContext_disableExitCodeChecking(testSuite->test_case_context);
326 }
327
328
329 /*
330  * Export a variable in the environment of the current test_runner.exe process.
331  */
332 errno_t TestSuite_export(TestSuite_t testSuite)
333 {
334         /* TODO trim */
335         const char* ptr;
336     const char* pos;
337     char __buffer[50] = {0};
338     char* line = testSuite->stream->line + strlen("export ");
339
340     line[strlen(line) -1] = '\0';
341
342     ptr = strchr(line,' ');
343     pos= ++ptr;
344     ptr =  strchr(line,'=');
345     strncpy(__buffer,pos,ptr - pos);
346         if(!SetEnvironmentVariable(__buffer,++ptr))
347         {
348                 setErrno(E_EXPORT_FAILED);
349                 Stream_printLine(testSuite->stream,export_failed_line_type);
350                 return getErrno();
351                 
352         }
353
354         return E_SUCCESS;
355 }
356
357 errno_t TestSuite_unset(TestSuite_t testSuite)
358 {
359         char line[128] = {0};
360     const char* ptr;
361     strcpy(line,testSuite->stream->line +2);
362         ptr = strchr(line,' ');
363     line[strlen(line) -1] = '\0';
364
365         if(!SetEnvironmentVariable(++ptr,NULL))
366         {
367
368                 setErrno(E_UNSET_FAILED);
369                 Stream_printLine(testSuite->stream,unset_failed_line_type);
370                 return getErrno();
371         }
372         
373         return E_SUCCESS;
374 }
375
376 /*
377  * Expected child output processing.
378  */
379 errno_t TestSuite_processExpectedChildOutput(TestSuite_t testSuite)
380 {
381         /* TODO : logic error*/
382         if(!TestCaseContext_isOutputCheckingEnabled(testSuite->test_case_context))
383                 return E_SUCCESS;
384         
385         /* TODO : trim */
386         TestCaseContext_appendExpectedOutput(testSuite->test_case_context,testSuite->stream->line + 2);
387         
388         return E_SUCCESS;
389 }
390
391 /*
392  * Child input processing.
393  */
394 errno_t TestSuite_processChildInput(TestSuite_t testSuite)
395 {
396         /* TODO : trim */
397         TestCaseContext_appendChildInput(testSuite->test_case_context,testSuite->stream->line + 2);
398
399         return E_SUCCESS;       
400 }
401
402 /* 
403  * Free the s_TestSuite pointed to by ptr.
404  */
405 void TestSuite_free(TestSuite_t testSuite)
406 {
407     ThreadEntry_t entry;
408     unsigned long count;
409     unsigned long i;
410     DWORD dwWaitResult;
411     bool steel_running;
412     bool last_async_process_error = false;
413     DWORD ExitCode = 0;
414     errno_t e = getErrno();
415
416         if(NULL == testSuite)
417                 return;
418
419     count = ThreadDynarray_getCount(testSuite->threads);
420
421     /* Wait for all asynchrone process */
422     if(NULL != testSuite->threads && count)
423     {
424         while(true)
425         {
426             steel_running = false;
427
428                 for(i = 0;i < count ; i++)
429             {
430                         entry = ThreadDynarray_at(testSuite->threads,i);
431                 
432                         GetExitCodeThread(entry->hThread,&ExitCode);
433                         
434                         if(STILL_ACTIVE == ExitCode)
435                 {
436                     Sleep(0);
437                                 steel_running = true;
438                 }
439                 }
440
441                 if(!steel_running)
442                         break;
443         }
444
445         for(i = 0;i <count;i++)
446         {
447             entry = ThreadDynarray_at(testSuite->threads,i);
448
449             if(entry->context->pi.hProcess)
450             {
451                 dwWaitResult=WaitForSingleObject(entry->hThread,INFINITE);
452
453                 if((WAIT_FAILED == dwWaitResult))
454                     TerminateThread(entry->hThread,0);
455                 else
456                     CloseHandle(entry->hThread);
457             }
458
459             /*if(((E_SUCCESS == e) || (E_EXIT_CODE_DONT_MATCH == e) || (E_OUTPUT_DONT_MATCH == e)) && !last_async_process_error)
460             {*/
461                 /* Child output and exit code checking */
462                 if(TestSuite_iSPostOutputCheckingEnabled(entry->context))
463                 {
464                     if(E_SUCCESS != TestSuite_checkChildOutput(entry->context))
465                         last_async_process_error = true;
466                 }
467
468                 if(TestSuite_iSExitCodeCheckingEnabled(entry->context))
469                 {
470                             if(E_SUCCESS != TestSuite_checkChildExitCode(entry->context))
471                         last_async_process_error = true;
472                 }
473             }
474
475             TestCaseContext_free(entry->context);
476         /*}*/
477
478         ThreadDynarray_destroy(testSuite->threads);
479     }
480
481     if(NULL != testSuite->test_case_context)
482                 TestCaseContext_free(testSuite->test_case_context);
483     
484         if(NULL != testSuite->stream)
485                 Stream_free(testSuite->stream);
486         
487         free(testSuite);
488 }
489
490 /*
491  * Check the child output.     
492  */
493 errno_t TestSuite_checkChildOutput(TestCaseContext_t context)
494 {
495         bool are_equals = false;
496         char str[256] = {0};
497
498         
499         if (context->expectedOutputBuffer->size==0 && context->outputBuffer->size==0)
500                 return E_SUCCESS;
501         
502         Buffer_chomp(context->outputBuffer);
503         Buffer_chomp(context->expectedOutputBuffer);
504         
505         
506         if (context->outputBuffer->size != context->expectedOutputBuffer->size || strcmp(context->outputBuffer->data, context->expectedOutputBuffer->data))
507         {
508                 strcpy(str,"<OUTPUT NOT MATCH            >  \n");
509                 TestSuite_print(str);
510                 
511         }
512     else
513     {
514                 are_equals = true;
515                 strcpy(str,"<OUTPUT MATCH                >  \n");
516                 TestSuite_print(str);
517                 
518                 
519     }
520     
521     memset(str,0,256);
522     
523     if(context->expectedOutputBuffer->size)
524     {
525         sprintf(str,"<EXPECTED                    >      SIZE (%4d) DATA (%s)\n",context->expectedOutputBuffer->size,context->expectedOutputBuffer->data);
526                 TestSuite_print(str);
527         }
528     else
529     {
530         scanf(str,"<EXPECTED                    >      SIZE (%4d) DATA (%s)\n",context->expectedOutputBuffer->size,"empty");
531                 TestSuite_print(str);
532         }
533         
534         memset(str,0,256);
535     
536         if(context->outputBuffer->size)
537         {
538                 sprintf(str,"<RECEIVED                    >      SIZE (%4d) DATA (%s)\n",context->outputBuffer->size,context->outputBuffer->data);
539                 TestSuite_print(str);
540         }
541         else
542         {
543                 sprintf(str,"<RECEIVED                    >      SIZE (%4d) DATA (%s)\n",context->outputBuffer->size,"empty");
544                 TestSuite_print(str);
545         }
546                 
547         Buffer_clear(context->expectedOutputBuffer);
548         Buffer_clear(context->outputBuffer);
549         
550         if(!are_equals)
551     {
552         setErrno(E_OUTPUT_DONT_MATCH);
553                 return getErrno();
554     }
555         
556         return E_SUCCESS;
557 }
558
559 /*
560  * Check the child process exit code.
561  */ 
562 errno_t TestSuite_checkChildExitCode(TestCaseContext_t context)
563 {
564                 bool __success = false;
565                 char str[256] = {0};
566                 
567                 sprintf(str,"<TEST CASE TERMINATED        >      %s %3ld\n",context->name,context->exitCode);
568                 TestSuite_print(str);
569                 
570                 memset(str,0,256);
571
572                 /* if a expected exit code was signaled, compare it with the real. */
573                 if(context->expectedExitCode != INVALID_EXIT_CODE)
574                 {
575                         if(context->expectedExitCode  != context->exitCode )
576                         {
577                                 
578                                 TestSuite_print("<EXIT CODE DON'T MATCH       >\n");
579                         }
580                         else
581                         {
582                 __success = true;
583                                 TestSuite_print("<EXIT CODE MATCH             >\n");
584                         }
585             sprintf(str,"<EXIT CODE EXPECTED          >      (%3d)\n",context->expectedExitCode);
586             TestSuite_print(str);
587
588             memset(str,0,256);
589
590             sprintf(str,"<EXIT CODE RETURNED          >      (%3d)\n",context->exitCode);
591              TestSuite_print(str);
592                 
593                         context->expectedExitCode = INVALID_EXIT_CODE;
594                 }
595
596         if(!__success)
597         {
598             setErrno(E_EXIT_CODE_DONT_MATCH);
599             return getErrno();
600         }
601
602         return E_SUCCESS;
603 }
604
605 /* 
606  * Terminate the test suite.
607  */
608 void TestSuite_terminate(TestSuite_t testSuite)
609 {
610         TestCaseContext_t context = testSuite->test_case_context;
611         
612         /* cleanup the child_input_stream/output buffers.       */
613         if(NULL != context->inputBuffer)
614                 Buffer_free(context->inputBuffer);
615         
616         if(NULL != context->outputBuffer)
617                 Buffer_free(context->outputBuffer);
618                 
619         if(NULL != context->expectedOutputBuffer)
620                 Buffer_free(context->expectedOutputBuffer);
621                 
622         /* close the file stream.                               */
623         if(NULL != testSuite->stream)
624                 Stream_free(testSuite->stream);
625         
626         
627 }
628
629
630 /*
631  * Print message
632  */
633 void TestSuite_print(const char* str)
634 {
635      char* t = (char*)calloc(1,20);
636      
637     __time(t);
638
639         EnterCriticalSection(&cs);
640     printf("%s   %s",t,str);
641     LeaveCriticalSection(&cs);
642
643     free(t);
644
645 }
646
647 unsigned long WINAPI TestSuite_asyncReadChildOutput(void* param)
648 {
649   char str[1024] = {0};
650   char __buffer[1024] = {0};
651   
652   DWORD nBytesRead;
653   DWORD nCharsWritten;
654   TestCaseContext_t context = (TestCaseContext_t)param;
655   HANDLE hPipeRead = context->hOutputRead;
656  
657
658   while (context->runThread)
659   {
660      if (!ReadFile(hPipeRead,str,sizeof(str),&nBytesRead,NULL) || !nBytesRead){
661         if (GetLastError() == ERROR_BROKEN_PIPE){
662            break;
663         }
664         else{
665                 /* TODO */
666                 context->threadExitCode = 1;
667                 exit(1);
668         }
669      }
670      
671      if(nBytesRead){
672         if(context->isOutputCheckingEnabled){
673             if(!Buffer_empty(context->outputBuffer))
674                 Buffer_clear(context->outputBuffer);
675
676                 TestSuite_print(str);
677
678
679             Buffer_append(context->outputBuffer,str);
680         }
681         
682         memset(str,0,1024);
683         memset(__buffer,0,1024);
684     }
685      
686   }
687         context->threadExitCode = 0;
688         return 0;
689 }
690
691 errno_t TestSuite_runAsyncTestCase(TestSuite_t testSuite)
692 {
693     DWORD ThreadId;
694     s_ThreadEntry_t entry;
695     /* = (ThreadEntry_t)calloc(1,sizeof(s_ThreadEntry_t));*/
696
697     TestCaseContext_t context = testSuite->test_case_context;
698     memset(&entry,0,sizeof(s_ThreadEntry_t));
699     entry.context = TestCaseContext_new();
700
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;
718
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);
723     Sleep(0);
724     setErrno(E_SUCCESS);
725
726     return getErrno();
727 }
728
729 unsigned long WINAPI TestSuite_runSyncTestCase( void* param)
730 {
731     STARTUPINFO si = {0};
732     SECURITY_ATTRIBUTES sa = {0};
733         DWORD dwWaitResult = 0;
734         DWORD dwExitCode = 0;
735         DWORD ThreadId;
736         DWORD nBytes = 0;
737     DWORD dwCreationMode = CREATE_NO_WINDOW;
738     char cmdLine[4098] = {0};
739
740     TestCaseContext_t context = (TestCaseContext_t)param;
741     context->started = true;
742         
743         
744         sa.nLength = sizeof(SECURITY_ATTRIBUTES);
745     sa.lpSecurityDescriptor = NULL;
746         /* The pipe handes can be inherited by the child. */
747         sa.bInheritHandle = TRUE;
748         
749         /* Create a write pipe handle for the child std output */
750         if(!CreatePipe(&(context->hChildStdoutReadTmp),&(context->hChildStdOutWrite),&sa,0))
751     {
752         setErrno(E_CANNOT_CREATE_CHILD_STDOUT_READ_HANDLE);
753                 return getErrno();
754     }
755         
756         /* 
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.
760          */
761         if(!DuplicateHandle(GetCurrentProcess(),(context->hChildStdOutWrite),GetCurrentProcess(),&(context->hChildStderr),0,TRUE,DUPLICATE_SAME_ACCESS))
762     {
763         setErrno(E_CANNOT_CREATE_CHILD_STDERR_READ_HANDLE);
764                 return getErrno();
765     }
766         
767         /* Create a read pipe handle for the child std input */
768         if(!CreatePipe(&(context->hChildStdInRead),&(context->hChildStdinWriteTmp),&sa,0))
769     {
770         setErrno(E_CANNOT_CREATE_CHILD_STDIN_WRITE_HANDLE);
771                 return getErrno();
772     }
773                 
774         
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. 
779          */
780         
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))
783     {
784         setErrno(E_CANNOT_CREATE_STDOUT_READ_HANDLE);
785                 return getErrno();
786     }
787         
788         
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))
791     {
792         setErrno(E_CANNOT_CREATE_STDIN_WRITE_HANDLE);
793                 return getErrno();
794     }
795         
796         
797         /* Close inheritable copies of the handles you do not want to be inherited. */
798         if(!CloseHandle((context->hChildStdoutReadTmp)))
799     {
800         setErrno(E_CANNOT_CLOSE_CHILD_STDIN_TEMPORY_HANDLE);
801                 return getErrno();
802     }
803
804         context->hChildStdoutReadTmp = NULL;
805         
806         if(!CloseHandle((context->hChildStdinWriteTmp)))
807     {
808         setErrno(E_CANNOT_CLOSE_CHILD_STDOUT_TEMPORY_HANDLE);
809                 return getErrno();
810     }
811         
812         
813         context->hChildStdinWriteTmp = NULL;
814
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;
821
822     if(context->createConsole)
823         dwCreationMode = CREATE_NEW_CONSOLE;
824
825     if(!Buffer_empty(context->commandLineBuffer)){
826         Buffer_chomp(context->commandLineBuffer);
827         sprintf(cmdLine,"%s %s",context->name,context->commandLineBuffer->data);
828     }
829     else
830         strcpy(cmdLine,context->name);
831
832
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);
836         return getErrno();
837     }
838     
839     if(!CloseHandle(context->pi.hThread)){
840         setErrno(E_CANNOT_CLOSE_PROCESS_THREAD_HANDLE);
841         return getErrno();
842     }
843     
844         
845         context->pi.hThread = NULL;
846         
847         /* close unnessary pipe handles. */
848         if(!CloseHandle(context->hChildStdOutWrite)){
849         setErrno(E_CANNOT_CLOSE_CHILD_STDOUT_HANDLE);
850         return getErrno();
851     }
852     
853     context->hChildStdOutWrite = NULL;
854     
855     if(!CloseHandle(context->hChildStdInRead)){
856         setErrno(E_CANNOT_CLOSE_CHILD_STDIN_HANDLE);
857         return getErrno();
858     }
859
860     context->hChildStdInRead = NULL;
861
862     if(!CloseHandle(context->hChildStderr)){
863         setErrno(E_CANNOT_CLOSE_CHILD_STDERR_HANDLE);
864         return getErrno();
865     }
866
867     context->hChildStderr = NULL;
868
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);
872                 return getErrno();
873         }
874         }
875     
876     context->hThread = CreateThread(&sa,0,TestSuite_asyncReadChildOutput,(LPVOID)context,0,&ThreadId);
877     Sleep(0);
878     
879     if(NULL == context->hThread){
880         setErrno(E_CANNOT_CREATE_READ_CHILD_OUTPUT_THREAD);
881         return getErrno();
882     }
883     
884
885     dwWaitResult = WaitForSingleObject(context->pi.hProcess,context->timeoutValue);
886
887     if(WAIT_FAILED == dwWaitResult)
888     {
889             TerminateProcess(context->pi.hProcess,0);
890             context->pi.hProcess = NULL;
891             context->runThread = false;
892
893             if(WAIT_FAILED == WaitForSingleObject(context->hThread,INFINITE)){
894                 setErrno(E_WAIT_THREAD_FAILED);
895                 return getErrno();
896             }
897
898             if(!CloseHandle(context->hThread)){
899                 setErrno(E_CANNOT_CLOSE_THREAD_HANDLE);
900                 return getErrno();
901             }
902
903             context->hThread = NULL;
904
905             if(!CloseHandle(context->hOutputRead)){
906                 setErrno(E_CANNOT_CLOSE_READ_HANDLE);
907                 return getErrno();
908             }
909
910             context->hOutputRead = NULL;
911
912             if(!CloseHandle(context->hInputWrite)){
913                 setErrno(E_CANNOT_CLOSE_WRITE_HANDLE);
914                 return getErrno();
915             }
916
917             context->hInputWrite = NULL;
918             setErrno(E_WAIT_FAILURE);
919             return getErrno();
920     }
921
922     if(WAIT_TIMEOUT == dwWaitResult)
923     {
924             TerminateProcess(context->pi.hProcess,0);
925             context->pi.hProcess = NULL;
926             context->runThread = false;
927
928             if(WAIT_FAILED == WaitForSingleObject(context->hThread,INFINITE)){
929                 setErrno(E_WAIT_THREAD_FAILED);
930                 return getErrno();
931             }
932
933             if(!CloseHandle(context->hThread)){
934                 setErrno(E_CANNOT_CLOSE_THREAD_HANDLE);
935                 return getErrno();
936             }
937
938             context->hThread = NULL;
939
940             if(!CloseHandle(context->hOutputRead)){
941                 setErrno(E_CANNOT_CLOSE_READ_HANDLE);
942                 return getErrno();
943             }
944
945
946             context->hOutputRead = NULL;
947
948             if(!CloseHandle(context->hInputWrite)){
949                 setErrno(E_CANNOT_CLOSE_WRITE_HANDLE);
950                 return getErrno();
951             }
952
953             context->hInputWrite = NULL;
954             setErrno(E_WAIT_TIMEOUT);
955             return getErrno();
956     }
957
958     /* all is ok . */
959
960     context->runThread = false;
961
962     if(WAIT_FAILED == WaitForSingleObject(context->hThread,INFINITE)){
963         setErrno(E_WAIT_THREAD_FAILED);
964         return getErrno();
965     }
966
967     if(!CloseHandle(context->hThread)){
968         setErrno(E_CANNOT_CLOSE_THREAD_HANDLE);
969         return getErrno();
970     }
971
972     context->hThread = NULL;
973
974     if(!CloseHandle(context->hOutputRead)){
975         setErrno(E_CANNOT_CLOSE_READ_HANDLE);
976         return getErrno();
977     }
978
979     context->hOutputRead = NULL;
980
981     if(!CloseHandle(context->hInputWrite)){
982         setErrno(E_CANNOT_CLOSE_WRITE_HANDLE);
983         return getErrno();
984     }
985
986     context->hInputWrite = NULL;
987         
988
989     /* Get the child exit code before close it. */
990         GetExitCodeProcess(context->pi.hProcess,&dwExitCode);
991     
992     context->exitCode = (int)dwExitCode;
993     
994     if(!CloseHandle(context->pi.hProcess)){
995         setErrno(E_CANNOT_CLOSE_PROCESS_HANDLE);
996         return getErrno();
997     }
998
999     context->runThread = true;
1000
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);
1005
1006             if (context->outputBuffer->size != context->expectedOutputBuffer->size || strcmp(context->outputBuffer->data, context->expectedOutputBuffer->data)){
1007                 setErrno(E_OUTPUT_DONT_MATCH);
1008             }
1009         }
1010      }
1011
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);
1016                         }
1017         }
1018      }
1019     
1020     context->pi.hProcess = NULL;
1021         return getErrno();
1022 }
1023
1024 bool TestSuite_iSPostOutputCheckingEnabled(TestCaseContext_t context)
1025 {
1026     if(!context->isPostOutputCheckingEnabled && context->isOutputCheckingEnabled){
1027                         return true;
1028     }
1029
1030     return false;
1031 }
1032
1033 bool TestSuite_iSExitCodeCheckingEnabled(TestCaseContext_t context)
1034 {
1035     return context->exitCodeCheckingEnabled;
1036 }
1037
1038 errno_t TestSuite_changeDir(TestSuite_t testSuite)
1039 {
1040     char* line = testSuite->stream->line + 5;
1041     size_t size = strlen(line);
1042
1043     while ((line[size-1] == '\n') || (line[size-1] == '\r')){
1044                 line[size-1] = '\0';
1045                 
1046                 if(size)
1047                         (size)--;
1048         }
1049
1050     if(!SetCurrentDirectory(line)){
1051         setErrno(E_CHANGE_DIRECTORY_FAILED);
1052         return E_CHANGE_DIRECTORY_FAILED;
1053     }
1054
1055     Stream_printLine(testSuite->stream,change_directory_line_type);
1056
1057     return E_SUCCESS;
1058 }
1059