1 /*
2 * This file is part of the openHiTLS project.
3 *
4 * openHiTLS is licensed under the Mulan PSL v2.
5 * You can use this software according to the terms and conditions of the Mulan PSL v2.
6 * You may obtain a copy of Mulan PSL v2 at:
7 *
8 * http://license.coscl.org.cn/MulanPSL2
9 *
10 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13 * See the Mulan PSL v2 for more details.
14 */
15
16 #include <setjmp.h>
17 #include <time.h>
18 #include <sys/time.h>
19
20 static jmp_buf env;
21 static int isSubProc = 0;
GetJmpAddress(void)22 int *GetJmpAddress(void)
23 {
24 return &isSubProc;
25 }
26
handleSignal()27 void handleSignal()
28 {
29 siglongjmp(env, 1);
30 }
31
PrintCaseName(FILE * logFile,bool showDetail,const char * name)32 static void PrintCaseName(FILE *logFile, bool showDetail, const char *name)
33 {
34 // print a minimum of 4 dots
35 int32_t dotCount = (OUTPUT_LINE_LENGTH - (int32_t)strlen(name) >= 4) ?
36 (OUTPUT_LINE_LENGTH - (int32_t)strlen(name)) : 4;
37 if (showDetail) {
38 Print("%s", name);
39 for (int32_t j = 0; j < dotCount; j++) {
40 Print(".");
41 }
42 }
43 (void)fprintf(logFile, "%s", name);
44 for (int32_t j = 0; j < dotCount; j++) {
45 (void)fprintf(logFile, ".");
46 }
47 }
48
ParseArgs(const TestArgs * arg,TestParam * info)49 static int ParseArgs(const TestArgs *arg, TestParam *info)
50 {
51 info->hexParamCount = 0;
52 info->intParamCount = 0;
53 info->paramCount = 0;
54 for (uint32_t i = 1; i < arg->argLen; i += 2) { // 2
55 if (strcmp(arg->arg[i], "int") == 0) {
56 if (ConvertInt(arg->arg[i + 1], &(info->intParam[info->intParamCount])) == 0) {
57 info->param[info->paramCount] = &(info->intParam[info->intParamCount]);
58 info->intParamCount++;
59 } else {
60 Print("\nERROR: Int param conversion failed for:\n\"%s\"\n", arg->arg[i + 1]);
61 return 1;
62 }
63 } else if (strcmp(arg->arg[i], "char") == 0) {
64 info->param[info->paramCount] = arg->arg[i+1];
65 } else if (strcmp(arg->arg[i], "Hex") == 0) {
66 if (ConvertHex(arg->arg[i + 1], &(info->hexParam[info->hexParamCount])) != 0) {
67 Print("\nERROR: Hex param conversion failed for:\n\"%s\"\n", arg->arg[i + 1]);
68 return 1;
69 }
70 info->param[info->paramCount] = &(info->hexParam[info->hexParamCount]);
71 info->hexParamCount++;
72 } else if (strcmp(arg->arg[i], "exp") == 0) {
73 int expId = 0;
74 if (ConvertInt(arg->arg[i + 1], &expId) != 0 ||
75 getExpression(expId, &(info->intParam[info->intParamCount])) != 0) {
76 Print("\nERROR: Macro param conversion failed\n");
77 return 1;
78 }
79 info->param[info->paramCount] = &(info->intParam[info->intParamCount]);
80 info->intParamCount++;
81 } else {
82 return 1;
83 }
84 info->paramCount++;
85 }
86
87 return 0;
88 }
89
PrintCaseNameResult(FILE * logFile,int vectorCount,int skipCount,int passCount,time_t beginTime)90 static int PrintCaseNameResult(FILE *logFile, int vectorCount, int skipCount, int passCount, time_t beginTime)
91 {
92 char suitePrefix[OUTPUT_LINE_LENGTH] = {0};
93 (void)snprintf_truncated_s(suitePrefix, sizeof(suitePrefix), "%s", suiteName);
94 size_t leftSize = sizeof(suitePrefix) - 1 - strlen(suitePrefix);
95 if (leftSize > 0) {
96 (void)memset_s(suitePrefix + strlen(suitePrefix), sizeof(suitePrefix) - strlen(suitePrefix), '.', leftSize);
97 }
98 int failCount = vectorCount - passCount - skipCount;
99 if (failCount == 0) {
100 Print("%sPASS || Run %-6d testcases, passed: %-6d, skipped: %-6d, failed: %-6d useSec:%-5lu\n", suitePrefix,
101 vectorCount, passCount, skipCount, failCount, time(NULL) - beginTime);
102 } else {
103 Print("%sFAIL || Run %-6d testcases, passed: %-6d, skipped: %-6d, failed: %-6d useSec:%-5lu\n", suitePrefix,
104 vectorCount, passCount, skipCount, failCount, time(NULL) - beginTime);
105 }
106
107 time_t rawtime;
108 struct tm *timeinfo;
109 (void)time(&rawtime);
110 timeinfo = localtime(&rawtime);
111 (void)fprintf(logFile, "End time: %s", asctime(timeinfo));
112 (void)fprintf(logFile, "Result: Run %d tests, Passed: %d, Skipped: %d, Failed: %d\n", vectorCount, passCount,
113 skipCount, failCount);
114 return failCount;
115 }
116
ProcessCases(FILE * logFile,bool showDetail,int targetFuncId)117 static int ProcessCases(FILE *logFile, bool showDetail, int targetFuncId)
118 {
119 (void)logFile;
120 volatile int vectorCount = 0;
121 volatile int passCount = 0;
122 volatile int skipCount = 0;
123 volatile int tryNum;
124 time_t beginTime = time(NULL);
125 struct timespec start, end;
126
127 for (volatile int i = 0; i < g_executeCount; i++) {
128 int funcId = strtoul(g_executeCases[i]->arg[0], NULL, 10); // 10
129 if (funcId < 0 || funcId > ((int)(sizeof(test_funcs)/sizeof(TestWrapper)))) {
130 Print("funcId false!\n");
131 return 1;
132 }
133 if ((targetFuncId != -1) && (funcId != targetFuncId)) {
134 continue;
135 }
136 (void)fprintf(logFile, "%s ", funcName[funcId]);
137 PrintCaseName(logFile, showDetail, g_executeCases[i]->testVectorName);
138 TestParam io;
139 if (ParseArgs(g_executeCases[i], &io) != 0) {
140 return -1;
141 }
142 TestWrapper fp = test_funcs[funcId];
143 g_testResult.result = TEST_RESULT_SUCCEED;
144 tryNum = 0;
145 clock_gettime(CLOCK_REALTIME, &start);
146 do {
147 if (tryNum > 0) {
148 sleep(10);
149 g_testResult.result = TEST_RESULT_SUCCEED;
150 }
151 tryNum++;
152 #ifdef ASAN
153 fp(io.param);
154 #else
155 // Executing Function
156 if (signal(SIGSEGV, handleSignal) == SIG_ERR) {
157 return -1;
158 }
159 int r = sigsetjmp(env, 1);
160 if (r == 0) {
161 fp(io.param);
162 } else if (r == 1){
163 g_testResult.result = TEST_RESULT_FAILED;
164 }
165 if (isSubProc != 0) {
166 break;
167 }
168 #endif
169 } while ((g_testResult.result == TEST_RESULT_FAILED) && (tryNum < FAIL_TRY_TIMES));
170 if (g_testResult.result == TEST_RESULT_SUCCEED) {
171 passCount++;
172 } else if (g_testResult.result == TEST_RESULT_SKIPPED) {
173 skipCount++;
174 }
175 vectorCount++;
176 clock_gettime(CLOCK_REALTIME, &end);
177 uint64_t elapsedms = (end.tv_sec - start.tv_sec) * 1000 + (end.tv_nsec - start.tv_nsec) / 1000000;
178 PrintResult(showDetail, g_executeCases[i]->testVectorName, elapsedms);
179 PrintLog(logFile);
180 for (int j = 0; j < io.hexParamCount; j++) {
181 FreeHex(&io.hexParam[j]);
182 }
183 if (isSubProc != 0) {
184 break;
185 }
186 }
187
188 return PrintCaseNameResult(logFile, vectorCount, skipCount, passCount, beginTime);
189 }
190
ExecuteTest(const char * fileName,bool showDetail,int targetFuncId)191 static int ExecuteTest(const char *fileName, bool showDetail, int targetFuncId)
192 {
193 if (LoadDataFile(fileName) != 0) {
194 return -1;
195 }
196 FILE *logFile = NULL;
197 char logFileName[MAX_FILE_NAME] = {0};
198 if (targetFuncId == -1) {
199 if (sprintf_s(logFileName, MAX_FILE_NAME, SUITE_LOG_FORMAT, suiteName) <= 0) {
200 Print("An error occurred while creating the log file\n");
201 return (-1);
202 }
203 } else {
204 if (sprintf_s(logFileName, MAX_FILE_NAME, FUNCTION_LOG_FORMAT, suiteName, funcName[targetFuncId]) <= 0) {
205 Print("An error occurred while creating the log file\n");
206 return (-1);
207 }
208 }
209 time_t rawtime = time(NULL);
210 if (rawtime == 0) {
211 return -1;
212 }
213 logFile = fopen(logFileName, "w");
214 if (logFile != NULL) {
215 struct tm *timeinfo;
216 timeinfo = localtime(&rawtime);
217 if (fprintf(logFile, "Begin time: %s", asctime(timeinfo)) <= 0) {
218 fclose(logFile);
219 return -1;
220 }
221 }
222 int rt = ProcessCases(logFile, showDetail, targetFuncId);
223 if (logFile != NULL) {
224 fclose(logFile);
225 }
226 return rt;
227 }
228
ProcessMutiArgs(int argc,char ** argv,const char * fileName)229 int ProcessMutiArgs(int argc, char **argv, const char *fileName)
230 {
231 int printDetail = 1;
232 int curTestCnt = 0;
233 int ret = -1;
234 int testCnt = sizeof(test_funcs) / sizeof(test_funcs[0]);
235 int *funcIndex = malloc(sizeof(int) * testCnt);
236 int found;
237
238 if (funcIndex == NULL) {
239 return ret;
240 }
241
242 for (int i = 1; i < argc; i++) {
243 if (strcmp(argv[i], "NO_DETAIL") == 0) {
244 printDetail = 0;
245 continue;
246 }
247 found = 0;
248 for (int j = 0; j < testCnt; j++) {
249 if (strcmp(argv[i], funcName[j]) == 0) {
250 funcIndex[curTestCnt++] = j;
251 found = 1;
252 break;
253 }
254 }
255 if (found != 1) {
256 Print("test function '%s' do not exist\n", argv[i]);
257 goto EXIT;
258 }
259 }
260
261 if (curTestCnt == 0) {
262 ret = ExecuteTest(fileName, printDetail, -1);
263 goto EXIT;
264 }
265
266 for (int i = 0; i < curTestCnt; i++) {
267 if (ExecuteTest(fileName, printDetail, funcIndex[i]) != 0) {
268 goto EXIT;
269 }
270 }
271 ret = 0;
272
273 EXIT:
274 free(funcIndex);
275 return ret;
276 }
277
main(int argc,char ** argv)278 int main(int argc, char **argv)
279 {
280 signal(SIGTTOU, SIG_IGN);
281 signal(SIGTTIN, SIG_IGN);
282 int ret = 0;
283 #ifndef PRINT_TO_TERMINAL
284 char testOutputName[MAX_FILE_NAME] = {0};
285 if (sprintf_s(testOutputName, MAX_FILE_NAME, "%s.output", suiteName) <= 0) {
286 return 0;
287 }
288 FILE *fp = fopen(testOutputName, "w");
289 if (fp == NULL) {
290 return 1;
291 }
292 SetOutputFile(fp);
293 #endif
294
295 char testName[MAX_FILE_PATH_LEN];
296 if (sprintf_s(testName, MAX_FILE_PATH_LEN, "%s.datax", suiteName) <= 0) {
297 goto EXIT;
298 }
299 if (argc == 1) {
300 ret = ExecuteTest(testName, 1, -1);
301 } else {
302 ret = ProcessMutiArgs(argc, argv, testName);
303 }
304 if (ret != 0) {
305 Print("execute test failed\n");
306 }
307 for (int i = 0; i < g_executeCount; i++) {
308 free(g_executeCases[i]);
309 }
310 EXIT:
311 #ifndef PRINT_TO_TERMINAL
312 (void)fclose(fp);
313 #endif
314 return ret;
315 }
316