Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
30fc661900cc1c29a9e9ebfd9c1537603db1562e
[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   case 1:
53     TestSuite_print("Run the test case from the console.\n");
54
55     ptr->stream->file = stdin;
56     return E_SUCCESS;
57
58   case 2:
59
60     if (E_SUCCESS != Stream_isValidFile(argv[1]))
61       return getErrno();
62
63     printf("\n\n Test runner : %s\n\n", argv[1]);
64
65     if (E_SUCCESS != Stream_openFile(ptr->stream, argv[1]))
66       return getErrno();
67
68     return E_SUCCESS;
69
70   default:
71     {
72       setErrno(E_BAD_USAGE);
73       return getErrno();
74     }
75   }
76 }
77
78 /* 
79  * Launch the test suite. 
80  */
81 void TestSuite_run(TestSuite_t testSuite)
82 {
83   Stream_t stream = testSuite->stream;
84
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))
89       continue;
90
91     /* Check if the current text line contains a invalid token. */
92     if (Stream_lineContainsInvalidToken(stream))
93       return;
94
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))
99         return;
100
101       /* Check the meta command validity. */
102       if (Stream_lineIsInvalidMetaCommand(stream))
103         return;
104
105       /* We have a valid meta command, process it */
106       if (E_SUCCESS != TestSuite_processMetaCommand(testSuite))
107         return;
108
109       continue;
110     }
111
112     /* Handle the comment. */
113     if (Stream_lineIsComment(stream)) {
114       Stream_printLine(testSuite->stream, comment_line_type);
115       continue;
116     }
117
118     /* Handle expected child output. */
119     if (Stream_lineIsExpectedChildOutput(stream)) {
120       if (E_SUCCESS != TestSuite_processExpectedChildOutput(testSuite))
121         return;
122
123       continue;
124     }
125
126     /* Handle expected child input. */
127     if (Stream_lineIsChildInput(stream)) {
128       if (E_SUCCESS != TestSuite_processChildInput(testSuite))
129         return;
130
131       continue;
132     }
133
134     if (Stream_lineIsChangeDir(stream)) {
135       if (E_SUCCESS != TestSuite_changeDir(testSuite))
136         return;
137
138       continue;
139     }
140
141     /* Handle synchrone synchrone test case. */
142     if (Stream_lineIsSyncTestCase(stream)) {
143       TestCaseContext_setName(testSuite->test_case_context,
144                               stream->line + 2);
145
146       TestSuite_runSyncTestCase(testSuite->test_case_context);
147
148
149       if (TestSuite_iSPostOutputCheckingEnabled
150           (testSuite->test_case_context)) {
151         TestSuite_checkChildOutput(testSuite->test_case_context);
152       }
153
154       if (TestSuite_iSExitCodeCheckingEnabled
155           (testSuite->test_case_context)) {
156         if (E_SUCCESS !=
157             TestSuite_checkChildExitCode(testSuite->test_case_context))
158           return;
159       }
160
161
162       if (E_SUCCESS != getErrno())
163         return;
164     }
165     /* Handle asynchrone synchrone test case. */
166     else if (Stream_lineIsAsyncTestCase(stream)) {
167       TestCaseContext_setName(testSuite->test_case_context,
168                               stream->line + 2);
169
170       if (E_SUCCESS != TestSuite_runAsyncTestCase(testSuite))
171         return;
172     } else {
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 /* 
184  * Meta command processing.
185  */
186 errno_t TestSuite_processMetaCommand(TestSuite_t testSuite)
187 {
188   Stream_t stream = testSuite->stream;
189
190   if (!strncmp("set timeout ", stream->line + 2, strlen("set timeout "))) {
191     TestSuite_setTimeout(testSuite);
192   } else
193       if (!strncmp
194           ("command line ", stream->line + 2, strlen("command line"))) {
195     TestSuite_setCommandLine(testSuite);
196   } else
197       if (!strncmp
198           ("enable output checking", stream->line + 2,
199            strlen("enable output checking"))) {
200     TestSuite_enableOutputChecking(testSuite);
201   } else
202       if (!strncmp
203           ("disable output checking", stream->line + 2,
204            strlen("disable output checking"))) {
205     TestSuite_disableOutputChecking(testSuite);
206   } else
207       if (!strncmp
208           ("enable post output checking", stream->line + 2,
209            strlen("enable post output checking"))) {
210     TestSuite_enablePostOutputChecking(testSuite);
211   } else
212       if (!strncmp
213           ("disable post output checking", stream->line + 2,
214            strlen("disable post output checking"))) {
215     TestSuite_disablePostOutputChecking(testSuite);
216   } else
217       if (!strncmp
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);
225   } else
226       if (!strncmp
227           ("create console", stream->line + 2, strlen("create console"))) {
228     TestSuite_createConsole(testSuite);
229   } else
230       if (!strncmp
231           ("create no console", stream->line + 2,
232            strlen("create no console"))) {
233     TestSuite_createNoConsole(testSuite);
234   } else
235       if (!strncmp
236           ("enable exit code checking", stream->line + 2,
237            strlen("enable exit code checking"))) {
238     TestSuite_enableExitCodeChecking(testSuite);
239   } else
240       if (!strncmp
241           ("disable exit code checking", stream->line + 2,
242            strlen("disable exit code checking"))) {
243     TestSuite_disableExitCodeChecking(testSuite);
244   } else {
245     /* TODO */
246     ASSERT(false);
247   }
248
249   return E_SUCCESS;
250
251 }
252
253 /* 
254  * Set the timeout of the test case context of the
255  * test suite.
256  */
257 void TestSuite_setTimeout(TestSuite_t testSuite)
258 {
259
260   int timeout = atoi(testSuite->stream->line + 2 + strlen("set timeout "));
261   TestCaseContext_setTimeout(testSuite->test_case_context, timeout);
262 }
263
264 /*
265  * Enable output checking for the current test case context.
266  */
267 void TestSuite_enableOutputChecking(TestSuite_t testSuite)
268 {
269   TestCaseContext_enableOutputChecking(testSuite->test_case_context);
270 }
271
272 void TestSuite_setCommandLine(TestSuite_t testSuite)
273 {
274   TestCaseContext_setCommandLine(testSuite->test_case_context,
275                                  testSuite->stream->line + 2 +
276                                  strlen("command line "));
277 }
278
279 /*
280  * Disable output checking for the current test case context.
281  */
282 void TestSuite_disableOutputChecking(TestSuite_t testSuite)
283 {
284   TestCaseContext_disableOutputChecking(testSuite->test_case_context);
285 }
286
287 /*
288  * Enable post output checking for the current test case context.
289  */
290 void TestSuite_enablePostOutputChecking(TestSuite_t testSuite)
291 {
292   TestCaseContext_enable_post_output_checking(testSuite->
293                                               test_case_context);
294 }
295
296 void TestSuite_createConsole(TestSuite_t testSuite)
297 {
298   TestCaseContext_createConsole(testSuite->test_case_context);
299 }
300
301 void TestSuite_createNoConsole(TestSuite_t testSuite)
302 {
303   TestCaseContext_createNoConsole(testSuite->test_case_context);
304 }
305
306 /*
307  * Disable post output checking for the current test case context.
308  */
309 void TestSuite_disablePostOutputChecking(TestSuite_t testSuite)
310 {
311   TestCaseContext_disablePostOutputChecking(testSuite->test_case_context);
312 }
313
314 /*
315  * Set the expected exit code of the current test case context of the test suite.
316  */
317 void TestSuite_setExpectedExitCode(TestSuite_t testSuite)
318 {
319   int expectedExitCode =
320       atoi(testSuite->stream->line + 2 + strlen("expect exit code "));
321   TestCaseContext_setExpectedExitCode(testSuite->test_case_context,
322                                       expectedExitCode);
323 }
324
325 void TestSuite_enableExitCodeChecking(TestSuite_t testSuite)
326 {
327   TestCaseContext_enableExitCodeChecking(testSuite->test_case_context);
328 }
329
330 void TestSuite_disableExitCodeChecking(TestSuite_t testSuite)
331 {
332   TestCaseContext_disableExitCodeChecking(testSuite->test_case_context);
333 }
334
335
336 /*
337  * Export a variable in the environment of the current test_runner.exe process.
338  */
339 errno_t TestSuite_export(TestSuite_t testSuite)
340 {
341   /* TODO trim */
342   const char *ptr;
343   const char *pos;
344   char __buffer[50] = { 0 };
345   char *line = testSuite->stream->line + strlen("export ");
346
347   line[strlen(line) - 1] = '\0';
348
349   ptr = strchr(line, ' ');
350   pos = ++ptr;
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);
356     return getErrno();
357
358   }
359
360   return E_SUCCESS;
361 }
362
363 errno_t TestSuite_unset(TestSuite_t testSuite)
364 {
365   char line[128] = { 0 };
366   const char *ptr;
367   strcpy(line, testSuite->stream->line + 2);
368   ptr = strchr(line, ' ');
369   line[strlen(line) - 1] = '\0';
370
371   if (!SetEnvironmentVariable(++ptr, NULL)) {
372
373     setErrno(E_UNSET_FAILED);
374     Stream_printLine(testSuite->stream, unset_failed_line_type);
375     return getErrno();
376   }
377
378   return E_SUCCESS;
379 }
380
381 /*
382  * Expected child output processing.
383  */
384 errno_t TestSuite_processExpectedChildOutput(TestSuite_t testSuite)
385 {
386   /* TODO : logic error */
387   if (!TestCaseContext_isOutputCheckingEnabled
388       (testSuite->test_case_context))
389     return E_SUCCESS;
390
391   /* TODO : trim */
392   TestCaseContext_appendExpectedOutput(testSuite->test_case_context,
393                                        testSuite->stream->line + 2);
394
395   return E_SUCCESS;
396 }
397
398 /*
399  * Child input processing.
400  */
401 errno_t TestSuite_processChildInput(TestSuite_t testSuite)
402 {
403   /* TODO : trim */
404   TestCaseContext_appendChildInput(testSuite->test_case_context,
405                                    testSuite->stream->line + 2);
406
407   return E_SUCCESS;
408 }
409
410 /* 
411  * Free the s_TestSuite pointed to by ptr.
412  */
413 void TestSuite_free(TestSuite_t testSuite)
414 {
415   ThreadEntry_t entry;
416   unsigned long count;
417   unsigned long i;
418   DWORD dwWaitResult;
419   bool steel_running;
420   bool last_async_process_error = false;
421   DWORD ExitCode = 0;
422   errno_t e = getErrno();
423
424   if (NULL == testSuite)
425     return;
426
427   count = ThreadDynarray_getCount(testSuite->threads);
428
429   /* Wait for all asynchrone process */
430   if (NULL != testSuite->threads && count) {
431     while (true) {
432       steel_running = false;
433
434       for (i = 0; i < count; i++) {
435         entry = ThreadDynarray_at(testSuite->threads, i);
436
437         GetExitCodeThread(entry->hThread, &ExitCode);
438
439         if (STILL_ACTIVE == ExitCode) {
440           Sleep(0);
441           steel_running = true;
442         }
443       }
444
445       if (!steel_running)
446         break;
447     }
448
449     for (i = 0; i < count; i++) {
450       entry = ThreadDynarray_at(testSuite->threads, i);
451
452       if (entry->context->pi.hProcess) {
453         dwWaitResult = WaitForSingleObject(entry->hThread, INFINITE);
454
455         if ((WAIT_FAILED == dwWaitResult))
456           TerminateThread(entry->hThread, 0);
457         else
458           CloseHandle(entry->hThread);
459       }
460
461       /*if(((E_SUCCESS == e) || (E_EXIT_CODE_DONT_MATCH == e) || (E_OUTPUT_DONT_MATCH == e)) && !last_async_process_error)
462          { */
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;
467       }
468
469       if (TestSuite_iSExitCodeCheckingEnabled(entry->context)) {
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
500       && context->outputBuffer->size == 0)
501     return E_SUCCESS;
502
503   Buffer_chomp(context->outputBuffer);
504   Buffer_chomp(context->expectedOutputBuffer);
505
506
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);
512
513   } else {
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     sprintf(str,
525             "<EXPECTED                    >      SIZE (%4d) DATA (%s)\n",
526             context->expectedOutputBuffer->size,
527             context->expectedOutputBuffer->data);
528     TestSuite_print(str);
529   } else {
530     scanf(str,
531           "<EXPECTED                    >      SIZE (%4d) DATA (%s)\n",
532           context->expectedOutputBuffer->size, "empty");
533     TestSuite_print(str);
534   }
535
536   memset(str, 0, 256);
537
538   if (context->outputBuffer->size) {
539     sprintf(str,
540             "<RECEIVED                    >      SIZE (%4d) DATA (%s)\n",
541             context->outputBuffer->size, context->outputBuffer->data);
542     TestSuite_print(str);
543   } else {
544     sprintf(str,
545             "<RECEIVED                    >      SIZE (%4d) DATA (%s)\n",
546             context->outputBuffer->size, "empty");
547     TestSuite_print(str);
548   }
549
550   Buffer_clear(context->expectedOutputBuffer);
551   Buffer_clear(context->outputBuffer);
552
553   if (!are_equals) {
554     setErrno(E_OUTPUT_DONT_MATCH);
555     return getErrno();
556   }
557
558   return E_SUCCESS;
559 }
560
561 /*
562  * Check the child process exit code.
563  */
564 errno_t TestSuite_checkChildExitCode(TestCaseContext_t context)
565 {
566   bool __success = false;
567   char str[256] = { 0 };
568
569   sprintf(str, "<TEST CASE TERMINATED        >      %s %3ld\n",
570           context->name, context->exitCode);
571   TestSuite_print(str);
572
573   memset(str, 0, 256);
574
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) {
578
579       TestSuite_print("<EXIT CODE DON'T MATCH       >\n");
580     } else {
581       __success = true;
582       TestSuite_print("<EXIT CODE MATCH             >\n");
583     }
584     sprintf(str, "<EXIT CODE EXPECTED          >      (%3d)\n",
585             context->expectedExitCode);
586     TestSuite_print(str);
587
588     memset(str, 0, 256);
589
590     sprintf(str, "<EXIT CODE RETURNED          >      (%3d)\n",
591             context->exitCode);
592     TestSuite_print(str);
593
594     context->expectedExitCode = INVALID_EXIT_CODE;
595   }
596
597   if (!__success) {
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     if (!ReadFile(hPipeRead, str, sizeof(str), &nBytesRead, NULL)
660         || !nBytesRead) {
661       if (GetLastError() == ERROR_BROKEN_PIPE) {
662         break;
663       } else {
664         /* TODO */
665         context->threadExitCode = 1;
666         exit(1);
667       }
668     }
669
670     if (nBytesRead) {
671       if (context->isOutputCheckingEnabled) {
672         if (!Buffer_empty(context->outputBuffer))
673           Buffer_clear(context->outputBuffer);
674
675         TestSuite_print(str);
676
677
678         Buffer_append(context->outputBuffer, str);
679       }
680
681       memset(str, 0, 1024);
682       memset(__buffer, 0, 1024);
683     }
684
685   }
686   context->threadExitCode = 0;
687   return 0;
688 }
689
690 errno_t TestSuite_runAsyncTestCase(TestSuite_t testSuite)
691 {
692   DWORD ThreadId;
693   s_ThreadEntry_t entry;
694   /* = (ThreadEntry_t)calloc(1,sizeof(s_ThreadEntry_t)); */
695
696   TestCaseContext_t context = testSuite->test_case_context;
697   memset(&entry, 0, sizeof(s_ThreadEntry_t));
698   entry.context = TestCaseContext_new();
699
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;
722
723   entry.hThread =
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);
729   Sleep(0);
730   setErrno(E_SUCCESS);
731
732   return getErrno();
733 }
734
735 unsigned long WINAPI TestSuite_runSyncTestCase(void *param)
736 {
737   STARTUPINFO si = { 0 };
738   SECURITY_ATTRIBUTES sa = { 0 };
739   DWORD dwWaitResult = 0;
740   DWORD dwExitCode = 0;
741   DWORD ThreadId;
742   DWORD nBytes = 0;
743   DWORD dwCreationMode = CREATE_NO_WINDOW;
744   char cmdLine[4098] = { 0 };
745
746   TestCaseContext_t context = (TestCaseContext_t) param;
747   context->started = true;
748
749
750   sa.nLength = sizeof(SECURITY_ATTRIBUTES);
751   sa.lpSecurityDescriptor = NULL;
752   /* The pipe handes can be inherited by the child. */
753   sa.bInheritHandle = TRUE;
754
755   /* Create a write pipe handle for the child std output */
756   if (!CreatePipe
757       (&(context->hChildStdoutReadTmp), &(context->hChildStdOutWrite), &sa,
758        0)) {
759     setErrno(E_CANNOT_CREATE_CHILD_STDOUT_READ_HANDLE);
760     return getErrno();
761   }
762
763   /* 
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.
767    */
768   if (!DuplicateHandle
769       (GetCurrentProcess(), (context->hChildStdOutWrite),
770        GetCurrentProcess(), &(context->hChildStderr), 0, TRUE,
771        DUPLICATE_SAME_ACCESS)) {
772     setErrno(E_CANNOT_CREATE_CHILD_STDERR_READ_HANDLE);
773     return getErrno();
774   }
775
776   /* Create a read pipe handle for the child std input */
777   if (!CreatePipe
778       (&(context->hChildStdInRead), &(context->hChildStdinWriteTmp), &sa,
779        0)) {
780     setErrno(E_CANNOT_CREATE_CHILD_STDIN_WRITE_HANDLE);
781     return getErrno();
782   }
783
784
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. 
789    */
790
791   /* Read handle for read operations on the child std output. */
792   if (!DuplicateHandle
793       (GetCurrentProcess(), (context->hChildStdoutReadTmp),
794        GetCurrentProcess(), &(context->hOutputRead), 0, FALSE,
795        DUPLICATE_SAME_ACCESS)) {
796     setErrno(E_CANNOT_CREATE_STDOUT_READ_HANDLE);
797     return getErrno();
798   }
799
800
801   /* Write handle for write operations on the child std input. */
802   if (!DuplicateHandle
803       (GetCurrentProcess(), (context->hChildStdinWriteTmp),
804        GetCurrentProcess(), &(context->hInputWrite), 0, FALSE,
805        DUPLICATE_SAME_ACCESS)) {
806     setErrno(E_CANNOT_CREATE_STDIN_WRITE_HANDLE);
807     return getErrno();
808   }
809
810
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);
814     return getErrno();
815   }
816
817   context->hChildStdoutReadTmp = NULL;
818
819   if (!CloseHandle(context->hChildStdinWriteTmp)) {
820     setErrno(E_CANNOT_CLOSE_CHILD_STDOUT_TEMPORY_HANDLE);
821     return getErrno();
822   }
823
824
825   context->hChildStdinWriteTmp = NULL;
826
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;
833
834   if (context->createConsole)
835     dwCreationMode = CREATE_NEW_CONSOLE;
836
837   if (!Buffer_empty(context->commandLineBuffer)) {
838     Buffer_chomp(context->commandLineBuffer);
839     sprintf(cmdLine, "%s %s", context->name,
840             context->commandLineBuffer->data);
841   } else
842     strcpy(cmdLine, context->name);
843
844
845   /* Create the child process. */
846   if (!CreateProcess
847       (NULL, cmdLine, NULL, NULL, TRUE, dwCreationMode, NULL, NULL, &si,
848        &(context->pi))) {
849     setErrno(E_CANNOT_CREATE_CHILD_PROCESS);
850     return getErrno();
851   }
852
853   if (!CloseHandle(context->pi.hThread)) {
854     setErrno(E_CANNOT_CLOSE_PROCESS_THREAD_HANDLE);
855     return getErrno();
856   }
857
858
859   context->pi.hThread = NULL;
860
861   /* close unnessary pipe handles. */
862   if (!CloseHandle(context->hChildStdOutWrite)) {
863     setErrno(E_CANNOT_CLOSE_CHILD_STDOUT_HANDLE);
864     return getErrno();
865   }
866
867   context->hChildStdOutWrite = NULL;
868
869   if (!CloseHandle(context->hChildStdInRead)) {
870     setErrno(E_CANNOT_CLOSE_CHILD_STDIN_HANDLE);
871     return getErrno();
872   }
873
874   context->hChildStdInRead = NULL;
875
876   if (!CloseHandle(context->hChildStderr)) {
877     setErrno(E_CANNOT_CLOSE_CHILD_STDERR_HANDLE);
878     return getErrno();
879   }
880
881   context->hChildStderr = NULL;
882
883   if (!Buffer_empty(context->inputBuffer)) {
884     if (!WriteFile
885         (context->hInputWrite, context->inputBuffer->data,
886          context->inputBuffer->size, &nBytes, NULL)) {
887       setErrno(E_CANNOT_WRITE_ON_CHILD_STDIN);
888       return getErrno();
889     }
890   }
891
892   context->hThread =
893       CreateThread(&sa, 0, TestSuite_asyncReadChildOutput,
894                    (LPVOID) context, 0, &ThreadId);
895   Sleep(0);
896
897   if (NULL == context->hThread) {
898     setErrno(E_CANNOT_CREATE_READ_CHILD_OUTPUT_THREAD);
899     return getErrno();
900   }
901
902
903   dwWaitResult =
904       WaitForSingleObject(context->pi.hProcess, context->timeoutValue);
905
906   if (WAIT_FAILED == dwWaitResult) {
907     TerminateProcess(context->pi.hProcess, 0);
908     context->pi.hProcess = NULL;
909     context->runThread = false;
910
911     if (WAIT_FAILED == WaitForSingleObject(context->hThread, INFINITE)) {
912       setErrno(E_WAIT_THREAD_FAILED);
913       return getErrno();
914     }
915
916     if (!CloseHandle(context->hThread)) {
917       setErrno(E_CANNOT_CLOSE_THREAD_HANDLE);
918       return getErrno();
919     }
920
921     context->hThread = NULL;
922
923     if (!CloseHandle(context->hOutputRead)) {
924       setErrno(E_CANNOT_CLOSE_READ_HANDLE);
925       return getErrno();
926     }
927
928     context->hOutputRead = NULL;
929
930     if (!CloseHandle(context->hInputWrite)) {
931       setErrno(E_CANNOT_CLOSE_WRITE_HANDLE);
932       return getErrno();
933     }
934
935     context->hInputWrite = NULL;
936     setErrno(E_WAIT_FAILURE);
937     return getErrno();
938   }
939
940   if (WAIT_TIMEOUT == dwWaitResult) {
941     TerminateProcess(context->pi.hProcess, 0);
942     context->pi.hProcess = NULL;
943     context->runThread = false;
944
945     if (WAIT_FAILED == WaitForSingleObject(context->hThread, INFINITE)) {
946       setErrno(E_WAIT_THREAD_FAILED);
947       return getErrno();
948     }
949
950     if (!CloseHandle(context->hThread)) {
951       setErrno(E_CANNOT_CLOSE_THREAD_HANDLE);
952       return getErrno();
953     }
954
955     context->hThread = NULL;
956
957     if (!CloseHandle(context->hOutputRead)) {
958       setErrno(E_CANNOT_CLOSE_READ_HANDLE);
959       return getErrno();
960     }
961
962
963     context->hOutputRead = NULL;
964
965     if (!CloseHandle(context->hInputWrite)) {
966       setErrno(E_CANNOT_CLOSE_WRITE_HANDLE);
967       return getErrno();
968     }
969
970     context->hInputWrite = NULL;
971     setErrno(E_WAIT_TIMEOUT);
972     return getErrno();
973   }
974
975   /* all is ok . */
976
977   context->runThread = false;
978
979   if (WAIT_FAILED == WaitForSingleObject(context->hThread, INFINITE)) {
980     setErrno(E_WAIT_THREAD_FAILED);
981     return getErrno();
982   }
983
984   if (!CloseHandle(context->hThread)) {
985     setErrno(E_CANNOT_CLOSE_THREAD_HANDLE);
986     return getErrno();
987   }
988
989   context->hThread = NULL;
990
991   if (!CloseHandle(context->hOutputRead)) {
992     setErrno(E_CANNOT_CLOSE_READ_HANDLE);
993     return getErrno();
994   }
995
996   context->hOutputRead = NULL;
997
998   if (!CloseHandle(context->hInputWrite)) {
999     setErrno(E_CANNOT_CLOSE_WRITE_HANDLE);
1000     return getErrno();
1001   }
1002
1003   context->hInputWrite = NULL;
1004
1005
1006   /* Get the child exit code before close it. */
1007   GetExitCodeProcess(context->pi.hProcess, &dwExitCode);
1008
1009   context->exitCode = (int) dwExitCode;
1010
1011   if (!CloseHandle(context->pi.hProcess)) {
1012     setErrno(E_CANNOT_CLOSE_PROCESS_HANDLE);
1013     return getErrno();
1014   }
1015
1016   context->runThread = true;
1017
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);
1023
1024       if (context->outputBuffer->size !=
1025           context->expectedOutputBuffer->size
1026           || strcmp(context->outputBuffer->data,
1027                     context->expectedOutputBuffer->data)) {
1028         setErrno(E_OUTPUT_DONT_MATCH);
1029       }
1030     }
1031   }
1032
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);
1037       }
1038     }
1039   }
1040
1041   context->pi.hProcess = NULL;
1042   return getErrno();
1043 }
1044
1045 bool TestSuite_iSPostOutputCheckingEnabled(TestCaseContext_t context)
1046 {
1047   if (!context->isPostOutputCheckingEnabled
1048       && context->isOutputCheckingEnabled) {
1049     return true;
1050   }
1051
1052   return false;
1053 }
1054
1055 bool TestSuite_iSExitCodeCheckingEnabled(TestCaseContext_t context)
1056 {
1057   return context->exitCodeCheckingEnabled;
1058 }
1059
1060 errno_t TestSuite_changeDir(TestSuite_t testSuite)
1061 {
1062   char *line = testSuite->stream->line + 5;
1063   size_t size = strlen(line);
1064
1065   while ((line[size - 1] == '\n') || (line[size - 1] == '\r')) {
1066     line[size - 1] = '\0';
1067
1068     if (size)
1069       (size)--;
1070   }
1071
1072   if (!SetCurrentDirectory(line)) {
1073     setErrno(E_CHANGE_DIRECTORY_FAILED);
1074     return E_CHANGE_DIRECTORY_FAILED;
1075   }
1076
1077   Stream_printLine(testSuite->stream, change_directory_line_type);
1078
1079   return E_SUCCESS;
1080 }