OnActivated() change for Accessibility and KeyboardFocus
[platform/core/uifw/dali-toolkit.git] / automated-tests / src / dali-toolkit / dali-toolkit-test-utils / test-harness.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "test-harness.h"
18 #include <stdlib.h>
19 #include <sys/types.h>
20 #include <sys/wait.h>
21 #include <unistd.h>
22 #include <vector>
23 #include <map>
24 #include <cstring>
25 #include <testcase.h>
26
27 namespace TestHarness
28 {
29
30 typedef std::map<int, TestCase> RunningTestCases;
31
32 namespace
33 {
34 const char* RED_COLOR="\e[1;31m";
35 const char* GREEN_COLOR="\e[1;32m";
36 const char* ASCII_RESET="\e[0m";
37 const char* ASCII_BOLD="\e[1m";
38 }
39
40
41 int RunTestCase( struct ::testcase_s& testCase )
42 {
43   int result = EXIT_STATUS_TESTCASE_FAILED;
44
45 // dont want to catch exception as we want to be able to get
46 // gdb stack trace from the first error
47 // by default tests should all always pass with no exceptions
48   if( testCase.startup )
49   {
50     testCase.startup();
51   }
52   result = testCase.function();
53   if( testCase.cleanup )
54   {
55     testCase.cleanup();
56   }
57
58   return result;
59 }
60
61 int RunTestCaseInChildProcess( struct ::testcase_s& testCase, bool suppressOutput )
62 {
63   int testResult = EXIT_STATUS_TESTCASE_FAILED;
64
65   int pid = fork();
66   if( pid == 0 ) // Child process
67   {
68     if( suppressOutput )
69     {
70       close(STDOUT_FILENO);
71       close(STDERR_FILENO);
72     }
73     exit( RunTestCase( testCase ) );
74   }
75   else if(pid == -1)
76   {
77     perror("fork");
78     exit(EXIT_STATUS_FORK_FAILED);
79   }
80   else // Parent process
81   {
82     int status = 0;
83     int childPid = waitpid(-1, &status, 0);
84     if( childPid == -1 )
85     {
86       perror("waitpid");
87       exit(EXIT_STATUS_WAITPID_FAILED);
88     }
89     if( WIFEXITED(status) )
90     {
91       if( childPid > 0 )
92       {
93         testResult = WEXITSTATUS(status);
94         if( testResult )
95         {
96           printf("Test case %s failed: %d\n", testCase.name, testResult);
97         }
98       }
99     }
100     else if(WIFSIGNALED(status) )
101     {
102       testResult = EXIT_STATUS_TESTCASE_ABORTED;
103
104 #ifdef WCOREDUMP
105       if(WCOREDUMP(status))
106       {
107         printf("Test case %s crashed\n", testCase.name);
108       }
109 #endif
110       printf("Test case %s exited with signal %s\n", testCase.name, strsignal(WTERMSIG(status)));
111     }
112     else if(WIFSTOPPED(status))
113     {
114       printf("Test case %s stopped with signal %s\n", testCase.name, strsignal(WSTOPSIG(status)));
115     }
116   }
117   return testResult;
118 }
119
120 void OutputStatistics( int numPasses, int numFailures )
121 {
122   const char* failureColor = GREEN_COLOR;
123   if( numFailures > 0 )
124   {
125     failureColor = RED_COLOR;
126   }
127   printf("\rNumber of test passes:   %s%4d (%5.2f%%)%s\n", ASCII_BOLD, numPasses, 100.0f * (float)numPasses / (numPasses+numFailures),  ASCII_RESET);
128   printf("%sNumber of test failures:%s %s%4d%s\n", failureColor, ASCII_RESET, ASCII_BOLD, numFailures, ASCII_RESET);
129
130 }
131
132
133 int RunAll(const char* processName, ::testcase tc_array[], bool reRunFailed)
134 {
135   int numFailures = 0;
136   int numPasses = 0;
137
138   // Run test cases in child process( to kill output/handle signals ), but run serially.
139   for( unsigned int i=0; tc_array[i].name; i++)
140   {
141     int result = RunTestCaseInChildProcess( tc_array[i], true );
142     if( result == 0 )
143     {
144       numPasses++;
145     }
146     else
147     {
148       numFailures++;
149     }
150   }
151
152   OutputStatistics(numPasses, numFailures);
153
154   return numFailures;
155 }
156
157
158
159 // Constantly runs up to MAX_NUM_CHILDREN processes
160 int RunAllInParallel(  const char* processName, ::testcase tc_array[], bool reRunFailed)
161 {
162   int numFailures = 0;
163   int numPasses = 0;
164
165   RunningTestCases children;
166   std::vector<int> failedTestCases;
167
168   // Fork up to MAX_NUM_CHILDREN processes, then
169   // wait. As soon as a proc completes, fork the next.
170
171   int nextTestCase = 0;
172   int numRunningChildren = 0;
173
174   while( tc_array[nextTestCase].name || numRunningChildren > 0)
175   {
176     // Create more children (up to the max number or til the end of the array)
177     while( numRunningChildren < MAX_NUM_CHILDREN && tc_array[nextTestCase].name )
178     {
179       int pid = fork();
180       if( pid == 0 ) // Child process
181       {
182         close(STDOUT_FILENO);
183         close(STDERR_FILENO);
184         exit( RunTestCase( tc_array[nextTestCase] ) );
185       }
186       else if(pid == -1)
187       {
188         perror("fork");
189         exit(EXIT_STATUS_FORK_FAILED);
190       }
191       else // Parent process
192       {
193         TestCase tc(nextTestCase, tc_array[nextTestCase].name);
194         children[pid] = tc;
195         nextTestCase++;
196         numRunningChildren++;
197       }
198     }
199
200     // Wait for the next child to finish
201
202     int status=0;
203     int childPid = waitpid(-1, &status, 0);
204     if( childPid == -1 )
205     {
206       perror("waitpid");
207       exit(EXIT_STATUS_WAITPID_FAILED);
208     }
209
210     if( WIFEXITED(status) )
211     {
212       if( childPid > 0 )
213       {
214         int testResult = WEXITSTATUS(status);
215         if( testResult )
216         {
217           printf("Test case %s failed: %d\n", children[childPid].testCaseName, testResult);
218           failedTestCases.push_back(children[childPid].testCase);
219           numFailures++;
220         }
221         else
222         {
223           numPasses++;
224         }
225         numRunningChildren--;
226       }
227     }
228
229     else if( WIFSIGNALED(status) || WIFSTOPPED(status))
230     {
231       status = WIFSIGNALED(status)?WTERMSIG(status):WSTOPSIG(status);
232
233       if( childPid > 0 )
234       {
235         RunningTestCases::iterator iter = children.find(childPid);
236         if( iter != children.end() )
237         {
238           printf("Test case %s exited with signal %s\n", iter->second.testCaseName, strsignal(status));
239           failedTestCases.push_back(iter->second.testCase);
240         }
241         else
242         {
243           printf("Unknown child process: %d signaled %s\n", childPid, strsignal(status));
244         }
245
246         numFailures++;
247         numRunningChildren--;
248       }
249     }
250   }
251
252   OutputStatistics( numPasses, numFailures );
253
254   if( reRunFailed )
255   {
256     for( unsigned int i=0; i<failedTestCases.size(); i++)
257     {
258       char* testCaseStrapline;
259       int numChars = asprintf(&testCaseStrapline, "Test case %s", tc_array[failedTestCases[i]].name );
260       printf("\n%s\n", testCaseStrapline);
261       for(int j=0; j<numChars; j++)
262       {
263         printf("=");
264       }
265       printf("\n");
266       RunTestCaseInChildProcess( tc_array[failedTestCases[i] ], false );
267     }
268   }
269
270   return numFailures;
271 }
272
273
274
275 int FindAndRunTestCase(::testcase tc_array[], const char* testCaseName)
276 {
277   int result = EXIT_STATUS_TESTCASE_NOT_FOUND;
278
279   for( int i = 0; tc_array[i].name; i++ )
280   {
281     if( !strcmp(testCaseName, tc_array[i].name) )
282     {
283       return RunTestCase( tc_array[i] );
284     }
285   }
286
287   printf("Unknown testcase name: \"%s\"\n", testCaseName);
288   return result;
289 }
290
291 void Usage(const char* program)
292 {
293   printf("Usage: \n"
294          "   %s <testcase name>\t\t Execute a test case\n"
295          "   %s \t\t Execute all test cases in parallel\n"
296          "   %s -r\t\t Execute all test cases in parallel, rerunning failed test cases\n",
297          program, program, program);
298 }
299
300 } // namespace