* This file is part of the openHiTLS project.
*
* openHiTLS is licensed under the Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#include "helper.h"
#include <dirent.h>
#include <string.h>
#include "crypt_utils.h"
#define INCLUDE_BASE "/* INCLUDE_BASE"
#define BEGIN_HEADER "/* BEGIN_HEADER */"
#define END_HEADER "/* END_HEADER */"
#define BEGIN_CASE "/* BEGIN_CASE */"
#define END_CASE "/* END_CASE */"
#define PRINT_TESTSUITES_TAG "</testsuites>\n"
#define PRINT_TESTSUITE_TAG " </testsuite>\n"
#define PRINT_TESTCASE_TAG " </testcase>\n"
#define PRINT_TESTCASE_LIST_TAG " <testcase name=\"%s\" status=\"run\" time=\"0\" classname=\"%s\" />\n"
#define PRINT_FAILURE_TAG " <failure message=\"failed\" type=\"\" />\n"
#define LINE_BREAK_SYMBOL '\n'
#define LINE_HEAD_SYMBOL '\r'
FunctionTable g_testFunc[MAX_TEST_FUCNTION_COUNT];
int g_testFuncCount = 0;
char g_expTable[MAX_EXPRESSION_COUNT][MAX_EXPRESSION_LEN];
int g_expCount = 0;
FILE *g_fpOutput = NULL;
int g_lineCount = 0;
char g_suiteFileName[MAX_FILE_PATH_LEN];
void SetOutputFile(FILE *fp)
{
g_fpOutput = fp;
}
FILE *GetOutputFile(void)
{
return g_fpOutput;
}
void FreeHex(Hex *data)
{
if (data == NULL) {
return;
}
data->len = 0;
if (data->x != NULL) {
free(data->x);
data->x = NULL;
}
}
Hex *NewHex(void)
{
Hex *data = (Hex *)malloc(sizeof(Hex));
if (data == NULL) {
return NULL;
}
data->len = 0;
data->x = NULL;
return data;
}
int IsInt(const char *str)
{
uint32_t i = 0;
if (str[0] == '-') {
i = 1;
}
for (; i < strlen(str); i++) {
if (str[i] > '9' || str[i] < '0') {
return 0;
}
}
return 1;
}
void Print(const char *fmt, ...)
{
#ifdef PRINT_TO_TERMINAL
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
#else
va_list args;
va_start(args, fmt);
(void)vfprintf(g_fpOutput, fmt, args);
va_end(args);
#endif
}
int ReadLine(FILE *file, char *buf, uint32_t bufLen, bool skipHash, bool skipEmptyLine)
{
int foundLine = 0;
int i;
char *ret = NULL;
while (!foundLine) {
ret = fgets(buf, bufLen, file);
if (ret == NULL) {
return -1;
}
g_lineCount++;
int len = strlen(buf);
if ((buf[0] == '#') && skipHash) {
continue;
}
if (!skipEmptyLine) {
foundLine = 1;
}
for (i = 0; i < len; i++) {
char cur = buf[i];
if (cur != ' ' && cur != LINE_BREAK_SYMBOL && cur != LINE_HEAD_SYMBOL) {
foundLine = 1;
}
if (cur == LINE_BREAK_SYMBOL || cur == LINE_HEAD_SYMBOL) {
buf[i] = '\0';
break;
}
}
}
return 0;
}
int SplitArguments(char *inStr, uint32_t inLen, char **outParam, uint32_t *paramLen)
{
uint32_t cur = 0;
uint32_t count = 0;
bool inString = false;
char *in = inStr;
char **param = outParam;
param[count] = &in[cur];
count++;
cur++;
if (count > *paramLen) {
return 1;
}
while (cur < inLen && in[cur] != '\0') {
if (in[cur] == '\"') {
inString = !inString;
}
if (in[cur] == ':' && !inString) {
if (cur == inLen - 1) {
param[count] = &in[cur];
} else {
param[count] = &in[cur + 1];
count++;
}
if (count > *paramLen) {
printf("Exceed maximum param limit, expect num %u, actual num %u\n",
*paramLen, count);
return 1;
}
in[cur] = '\0';
}
cur++;
}
if (in[cur - 1] == '\n') {
in[cur - 1] = '\0';
}
*paramLen = count;
if (inString) {
return 1;
}
return 0;
}
static int g_fuzzEnd = 0;
int CheckTag(char *in, uint32_t len)
{
char *cur = in;
while (*cur == ' ') {
cur++;
}
uint32_t beginHeaderLen = strlen(BEGIN_HEADER);
uint32_t endHeaderLen = strlen(END_HEADER);
uint32_t beginCaseLen = strlen(BEGIN_CASE);
uint32_t endCaseLen = strlen(END_CASE);
uint32_t includeBaseLen = strlen(INCLUDE_BASE);
if ((len >= beginHeaderLen) && (strlen(cur) >= beginHeaderLen) &&
(strncmp(cur, BEGIN_HEADER, beginHeaderLen) == 0)) {
return TAG_BEGIN_HEADER;
} else if ((len >= endHeaderLen) && (strlen(cur) >= endHeaderLen) &&
(strncmp(cur, END_HEADER, endHeaderLen) == 0)) {
return TAG_END_HEADER;
} else if ((len >= beginCaseLen) && (strlen(cur) >= beginCaseLen) &&
(strncmp(cur, BEGIN_CASE, beginCaseLen) == 0)) {
return TAG_BEGIN_CASE;
} else if ((len >= endCaseLen) && (strlen(cur) >= endCaseLen) &&
(strncmp(cur, END_CASE, endCaseLen) == 0)) {
return TAG_END_CASE;
} else if ((len >= includeBaseLen) && (strlen(cur) >= includeBaseLen) &&
(strncmp(cur, INCLUDE_BASE, includeBaseLen) == 0)) {
return TAG_INCLUDE_BASE;
}
return TAG_NOT_TAG;
}
static int ClearVoid(const char *in, const uint32_t inLen, uint32_t *cur, uint32_t *prev)
{
uint32_t localCur = *cur;
uint32_t localPrev;
while (localCur < inLen && in[localCur] == ' ') {
localCur++;
}
localPrev = localCur;
if (strncmp(&in[localCur], "void", strlen("void")) != 0) {
return 1;
}
localCur += strlen("void");
while (localCur < inLen && in[localCur] == ' ') {
localCur++;
}
localPrev = localCur;
*cur = localCur;
*prev = localPrev;
return 0;
}
static int NextArgument(const char *in, const uint32_t inLen, uint32_t *cur)
{
uint32_t localCur = *cur;
while (localCur < inLen && in[localCur] != ',' && in[localCur] != ')') {
localCur++;
}
if (localCur >= inLen) {
return 1;
}
*cur = localCur;
return 0;
}
static int CheckType(const char *in, const uint32_t cur, const uint32_t prev, int *outType)
{
int *type = outType;
if ((cur - prev == strlen("int")) && (strncmp(&in[prev], "int", strlen("int")) == 0)) {
*type = ARG_TYPE_INT;
} else if ((cur - prev == strlen("Hex")) && (strncmp(&in[prev], "Hex", strlen("Hex")) == 0)) {
*type = ARG_TYPE_HEX;
} else if ((cur - prev == strlen("char")) && (strncmp(&in[prev], "char", strlen("char")) == 0)) {
*type = ARG_TYPE_STR;
} else {
return 1;
}
return 0;
}
int ReadFunction(const char *in, const uint32_t inLen, char *outFuncName, uint32_t outLen, int argv[MAX_ARGUMENT_COUNT],
uint32_t *argCount)
{
uint32_t cur = 0;
uint32_t prev = 0;
char *funcName = outFuncName;
if (ClearVoid(in, inLen, &cur, &prev) != 0) {
return 1;
}
while (cur < inLen && in[cur] != '(') {
cur++;
}
if (cur >= inLen) {
return 1;
}
if ((size_t)(cur - prev) >= outLen) {
return 1;
}
memcpy(funcName, &in[prev], (size_t)(cur - prev));
funcName[cur - prev] = '\0';
cur++;
uint32_t count = 0;
while (cur < inLen) {
while (cur < inLen && in[cur] == ' ') {
cur++;
}
prev = cur;
while (cur < inLen && in[cur] != ' ' && in[cur] != ',' && in[cur] != '*' && in[cur] != ')') {
cur++;
}
if (in[cur] == ')') {
break;
}
if (cur == inLen || in[cur] == ',') {
return 1;
}
int type = -1;
if (CheckType(in, cur, prev, &type) != 0) {
Print("******\nERROR: check type failed at: \n");
return 1;
}
argv[count] = type;
count++;
if (NextArgument(in, inLen, &cur) != 0) {
return 1;
}
if (in[cur] == ')') {
break;
}
cur++;
}
*argCount = count;
return 0;
}
int AddFunction(const char *funcName, int argv[MAX_ARGUMENT_COUNT], const uint32_t argCount)
{
if (g_testFuncCount >= MAX_TEST_FUCNTION_COUNT || argCount > MAX_ARGUMENT_COUNT) {
return 1;
}
if (strlen(funcName) >= MAX_TEST_FUNCTION_NAME) {
return 1;
}
strcpy(g_testFunc[g_testFuncCount].name, funcName);
g_testFunc[g_testFuncCount].argCount = argCount;
for (uint32_t i = 0; i < argCount; i++) {
g_testFunc[g_testFuncCount].argType[i] = argv[i];
}
g_testFunc[g_testFuncCount].id = g_testFuncCount;
g_testFuncCount++;
return 0;
}
int GenFunctionWrapper(FILE *file, FunctionTable *function)
{
int ret;
ret = fprintf(file, "void %s_wrapper(void **param)\n", function->name);
if (ret < 0) {
return 1;
}
ret = fprintf(file, "{\n");
if (ret < 0) {
return 1;
}
ret = fprintf(file, " (void)signal(SIGALRM, handleAlarmSignal);\n");
if (ret < 0) {
return 1;
}
ret = fprintf(file, " alarm(600u);\n");
if (ret < 0) {
return 1;
}
if (function->argCount == 0) {
ret = fprintf(file, " (void) param;\n");
if (ret < 0) {
return 1;
}
}
ret = fprintf(file, " %s(", function->name);
if (ret < 0) {
return 1;
}
for (uint32_t i = 0; i < function->argCount; i++) {
if (function->argType[i] == ARG_TYPE_INT) {
ret = fprintf(file, "*((int*)param[%d])", (int)i);
if (ret < 0) {
return 1;
}
} else if (function->argType[i] == ARG_TYPE_STR) {
ret = fprintf(file, "(char*)param[%d]", (int)i);
if (ret < 0) {
return 1;
}
} else if (function->argType[i] == ARG_TYPE_HEX) {
ret = fprintf(file, "(Hex*)param[%d]", (int)i);
if (ret < 0) {
return 1;
}
}
if (i != function->argCount - 1) {
ret = fprintf(file, ", ");
if (ret < 0) {
return 1;
}
}
}
ret = fprintf(file,
");\n"
" alarm(0);\n"
"#if defined(HITLS_BSL_ERR)\n"
" BSL_ERR_ClearError();\n"
"#endif\n"
"}\n\n");
if (ret < 0) {
return 1;
}
return 0;
}
int GenFunctionPointer(FILE *file)
{
if (file == NULL) {
return 1;
}
int ret;
ret = fprintf(file, "%s\n\n", "typedef void (*TestWrapper)(void **param);");
if (ret < 0) {
return 1;
}
ret = fprintf(file, "%s\n%s\n", "TestWrapper test_funcs[] = ", "{");
if (ret < 0) {
return 1;
}
for (int i = 0; i < g_testFuncCount; i++) {
ret = fprintf(file, " %s_wrapper, \n", g_testFunc[i].name);
if (ret < 0) {
return 1;
}
}
ret = fprintf(file, "%s\n", "};");
if (ret < 0) {
return 1;
}
return 0;
}
static int ConnectFunction(char *lineBuf, uint32_t bufLen, FILE *fp)
{
char buf[MAX_FUNCTION_LINE_LEN];
bool reachEnd = false;
int ret = 0;
while (!reachEnd) {
for (int i = 0; lineBuf[i] != '\0'; i++) {
if (lineBuf[i] == ')') {
ret = 0;
reachEnd = true;
}
if (lineBuf[i] == '{') {
ret = 1;
reachEnd = true;
}
}
if (reachEnd) {
break;
}
if (ReadLine(fp, buf, MAX_FUNCTION_LINE_LEN, 0, 0) == 0) {
size_t used = strlen(lineBuf);
size_t add = strlen(buf);
if (used + add + 1 > bufLen) {
return 1;
}
strcat(lineBuf, buf);
} else {
return 1;
}
}
return ret;
}
int ScanAllFunction(FILE *inFile, FILE *outFile)
{
char buf[MAX_FUNCTION_LINE_LEN];
int ret = 0;
uint32_t len = MAX_ARGUMENT_COUNT;
bool inFunction = false;
bool isDeclaration = true;
int arguments[MAX_ARGUMENT_COUNT];
char funcName[MAX_TEST_FUNCTION_NAME];
while (ReadLine(inFile, buf, MAX_FUNCTION_LINE_LEN, 0, 0) == 0) {
int curTag = CheckTag(buf, strlen(buf));
if (curTag == TAG_NOT_TAG) {
if (!inFunction) {
fprintf(outFile, "%s\n", buf);
continue;
}
} else if (curTag == TAG_BEGIN_CASE) {
if (!inFunction) {
inFunction = true;
isDeclaration = true;
continue;
}
Print("ERROR: missing end case tag\n");
return 1;
} else if (curTag == TAG_END_CASE) {
if (inFunction) {
inFunction = false;
fprintf(outFile, "\n");
continue;
}
return 1;
} else {
return 1;
}
if (isDeclaration) {
if (ConnectFunction(buf, sizeof(buf), inFile) != 0) {
Print("******\nERROR: connect function failed at: \n");
Print("%s\n", buf);
return 1;
}
ret = ReadFunction(buf, strlen(buf), funcName, sizeof(funcName), arguments, &len);
if (ret != 0) {
Print("*******\nERROR: Read function failed at: \n");
Print("%s\n", buf);
return ret;
}
ret = AddFunction(funcName, arguments, len);
if (ret != 0) {
return ret;
}
isDeclaration = false;
len = MAX_ARGUMENT_COUNT;
}
(void)fprintf(outFile, "%s\n", buf);
}
return 0;
}
static int IncludeBase(char *line, uint32_t len, FILE *outFile, const char *dir)
{
if (len < strlen(INCLUDE_BASE)) {
return 1;
}
char *name = &line[strlen(INCLUDE_BASE)];
while (*name == ' ') {
name++;
}
if (*name == '\0') {
return 1;
}
char *end = name;
while (*end != ' ') {
end++;
}
*end = '\0';
char fileBuf[MAX_FILE_PATH_LEN];
if (snprintf(fileBuf, MAX_FILE_PATH_LEN, BASE_FILE_FORMAT, dir, name) < 0) {
return 1;
}
g_lineCount = 0;
FILE *fpBase = fopen(fileBuf, "r");
if (fpBase == NULL) {
Print("ERROR:Open the base file. %s An error occurred when\n", fileBuf);
return 1;
}
int ret;
char buf[MAX_FUNCTION_LINE_LEN];
while (ReadLine(fpBase, buf, MAX_FUNCTION_LINE_LEN, 0, 0) == 0) {
ret = fprintf(outFile, "%s\n", buf);
if (ret < 0) {
goto EXIT;
}
}
EXIT:
if (fclose(fpBase) != 0) {
Print("base file close failed\n");
}
return 0;
}
int WriteHeader(FILE *outFile)
{
if (fprintf(outFile, "#include \"helper.h\"\n#include \"test.h\"\n#include <time.h>\n#include <unistd.h>\n") < 0) {
return 1;
}
return 0;
}
int ScanHeader(FILE *inFile, FILE *outFile, const char *dir)
{
char buf[MAX_FUNCTION_LINE_LEN];
bool inHeader = false;
while (ReadLine(inFile, buf, MAX_FUNCTION_LINE_LEN, 0, !inHeader) == 0) {
int curTag = CheckTag(buf, strlen(buf));
if (curTag == TAG_BEGIN_HEADER) {
if (!inHeader) {
inHeader = true;
} else {
Print("******\nERROR: duplicate begin header tag\n");
return 1;
}
} else if (curTag == TAG_END_HEADER) {
if (inHeader) {
(void)fprintf(outFile, "%s\n", buf);
return 0;
} else {
Print("******\nERROR: found end header without begin\n");
return 1;
}
} else if (curTag == TAG_INCLUDE_BASE) {
int tmpLineCount = g_lineCount;
if (IncludeBase(buf, strlen(buf), outFile, dir) != 0) {
Print("******\nERROR: include base file failed\n");
return 1;
}
g_lineCount = tmpLineCount;
continue;
} else if (curTag != TAG_NOT_TAG) {
Print("******\nERROR: missing end header tag\n");
return 1;
}
(void)fprintf(outFile, "%s\n", buf);
}
return 0;
}
static int AddExp(const char *exp)
{
if (g_expCount >= MAX_EXPRESSION_COUNT) {
Print("Too much macros. Max macro count is %d\n", MAX_EXPRESSION_COUNT);
return -1;
}
for (int i = 0; i < g_expCount; i++) {
if (strcmp(exp, g_expTable[i]) == 0) {
return i;
}
}
if (strlen(exp) >= MAX_EXPRESSION_LEN) {
Print("Macro too long, max length is %d\n", MAX_EXPRESSION_LEN);
return -1;
}
strcpy(g_expTable[g_expCount], exp);
g_expCount++;
return g_expCount - 1;
}
static int GetFuncIdByName(const char *name, uint32_t len)
{
int funcId = -1;
for (int i = 0; i < g_testFuncCount; i++) {
if ((len < MAX_TEST_FUNCTION_NAME) && (strcmp(name, g_testFunc[i].name) == 0)) {
funcId = i;
break;
}
}
return funcId;
}
int GenDatax(FILE *inFile, FILE *outFile)
{
char buf[MAX_DATA_LINE_LEN];
char title[MAX_DATA_LINE_LEN];
int ret;
int funcId = -1;
char *param[MAX_ARGUMENT_COUNT];
uint32_t paramLen = MAX_ARGUMENT_COUNT;
while (ReadLine(inFile, title, MAX_DATA_LINE_LEN, 1, 1) == 0) {
ret = fprintf(outFile, "%s\n", title);
if (ret < 0) {
return 1;
}
if ((ReadLine(inFile, buf, MAX_DATA_LINE_LEN, 1, 1) != 0)) {
return 1;
}
paramLen = MAX_ARGUMENT_COUNT;
ret = SplitArguments(buf, strlen(buf), param, ¶mLen);
if (ret != 0) {
Print("******\nERROR: Generate datax failed: split argument failed at testcase:\n");
Print("%s\n", title);
return ret;
}
funcId = GetFuncIdByName(param[0], strlen(param[0]));
if (funcId == -1) {
Print("******\nERROR: Generate datax failed: no function id for %s at testcase:\n", param[0]);
Print("%s\n", title);
return 1;
}
if (paramLen != g_testFunc[funcId].argCount + 1) {
Print("******\nERROR: Generate datax failed: invalid argument count for function %s at testcase:\n",
param[0]);
Print("%s\n", title);
return 1;
}
ret = fprintf(outFile, "%d:", funcId);
if (ret < 0) {
return 1;
}
int expId = 0;
for (uint32_t i = 0; i < g_testFunc[funcId].argCount; i++) {
if (g_testFunc[funcId].argType[i] == ARG_TYPE_INT && (IsInt(param[i + 1]) == 1)) {
ret = fprintf(outFile, "int:%s", param[i + 1]);
} else if (g_testFunc[funcId].argType[i] == ARG_TYPE_INT && (!IsInt(param[i + 1]))) {
expId = AddExp(param[i + 1]);
ret = fprintf(outFile, "exp:%d", expId);
} else if (g_testFunc[funcId].argType[i] == ARG_TYPE_STR) {
ret = fprintf(outFile, "char:%s", param[i + 1]);
} else if (g_testFunc[funcId].argType[i] == ARG_TYPE_HEX) {
ret = fprintf(outFile, "Hex:%s", param[i + 1]);
} else {
Print("invalid argument type\n");
return 1;
}
if (ret < 0) {
return 1;
}
if (i != g_testFunc[funcId].argCount - 1) {
ret = fprintf(outFile, ":");
}
if (expId == -1) {
return 1;
}
expId = 0;
}
ret = fprintf(outFile, "\n\n");
if (ret < 0) {
return 1;
}
}
return 0;
}
int GenExpTable(FILE *outFile)
{
int ret;
ret = fprintf(outFile, "int getExpression(int expId, int *out)\n{\n");
if (ret < 0) {
return 1;
}
if (g_expCount == 0) {
ret = fprintf(outFile, " (void) out;\n (void) expId;\n");
if (ret < 0) {
return 1;
}
}
ret = fprintf(outFile, " int ret = 0;\n");
if (ret < 0) {
return 1;
}
ret = fprintf(outFile, " switch (expId)\n {\n");
if (ret < 0) {
return 1;
}
for (int i = 0; i < g_expCount; i++) {
ret = fprintf(outFile, " case %d:\n", i);
if (ret < 0) {
return 1;
}
ret = fprintf(outFile, " *out = %s;\n", g_expTable[i]);
if (ret < 0) {
return 1;
}
ret = fprintf(outFile, " break;\n");
if (ret < 0) {
return 1;
}
}
ret = fprintf(outFile, " default:\n");
if (ret < 0) {
return 1;
}
ret = fprintf(outFile, " ret = 1;\n");
if (ret < 0) {
return 1;
}
ret = fprintf(outFile, " break;\n");
if (ret < 0) {
return 1;
}
ret = fprintf(outFile, " }\n return ret;\n}\n");
if (ret < 0) {
return 1;
}
return 0;
}
int LoadFunctionName(FILE *outFile)
{
int ret;
ret = fprintf(outFile, "const char * funcName[] = {\n");
if (ret < 0) {
return 1;
}
for (int i = 0; i < g_testFuncCount; i++) {
ret = fprintf(outFile, " \"%s\",\n", g_testFunc[i].name);
if (ret < 0) {
return 1;
}
}
ret = fprintf(outFile, "};\n\n");
if (ret < 0) {
return 1;
}
return 0;
}
int LoadHelper(FILE *inFile, FILE *outFile)
{
int ret;
char buf[MAX_FUNCTION_LINE_LEN];
if (inFile == NULL || outFile == NULL) {
return 1;
}
while (fgets(buf, MAX_FUNCTION_LINE_LEN, inFile) != NULL) {
ret = fprintf(outFile, "%s", buf);
if (ret < 0) {
return 1;
}
}
(void)fprintf(outFile, "\n\n");
return 0;
}
int SplitHex(Hex *src, Hex *dest, int max)
{
uint32_t blocks = src->len / SPILT_HEX_BLOCK_SIZE;
uint32_t remain = src->len % SPILT_HEX_BLOCK_SIZE;
uint32_t i;
if (blocks + 1 > (uint32_t)max) {
return 0;
}
for (i = 0; i < blocks; i++) {
dest[i].x = src->x + i * SPILT_HEX_BLOCK_SIZE;
dest[i].len = SPILT_HEX_BLOCK_SIZE;
}
if (remain == 0) {
return blocks;
} else {
dest[i].x = src->x + i * SPILT_HEX_BLOCK_SIZE;
dest[i].len = remain;
return blocks + 1;
}
}
int SplitHexRand(Hex *src, Hex *dest, int max)
{
uint32_t left = src->len;
int id = 0;
if (left <= 3) {
dest[id].x = src->x;
dest[id].len = left;
id++;
return id;
}
while (left > 3) {
dest[id].x = src->x + (src->len - left);
uint16_t clen = GET_UINT16_LE(dest[id].x, 0);
dest[id].len = clen > left ? left : clen;
left -= dest[id].len;
id++;
if (id > max - 1) {
break;
}
}
if (left > 0) {
dest[id - 1].len += left;
}
return id;
}
FILE *OpenFile(const char *name, const char *option, const char *format)
{
FILE *fp = NULL;
char fileBuf[MAX_FILE_PATH_LEN];
if (snprintf(fileBuf, MAX_FILE_PATH_LEN, format, name) < 0) {
Print("argument too long\n");
return NULL;
}
fp = fopen(fileBuf, option);
return fp;
}
int StripDir(const char *in, char *suiteName, const uint32_t suiteNameLen, char *dir, const uint32_t dirNameLen)
{
int len = strlen(in);
int begin = len - 1;
char *localDir = dir;
char *localSuiteName = suiteName;
while (begin >= 0 && in[begin] != '/') {
begin--;
}
if (begin < 0) {
return 1;
}
if ((size_t)begin >= dirNameLen) {
return 1;
}
memcpy(localDir, in, (size_t)begin);
localDir[begin] = '\0';
if (strlen(&in[begin + 1]) >= suiteNameLen) {
return 1;
}
strcpy(localSuiteName, &in[begin + 1]);
if (strlen(&in[begin + 1]) >= MAX_FILE_PATH_LEN) {
return 1;
}
strcpy(g_suiteFileName, &in[begin + 1]);
return 0;
}
int ScanFunctionFile(FILE *fpIn, FILE *fpOut, const char *dir)
{
int ret;
ret = ScanHeader(fpIn, fpOut, dir);
if (ret != 0) {
Print("scan header failed\n");
return 1;
}
ret = ScanAllFunction(fpIn, fpOut);
if (ret != 0) {
Print("scan function failed\n");
return 1;
}
if (fprintf(fpOut, "\n void handleAlarmSignal(int signum)\n{\n\
(void)signum; \n\
const char msg[] = \"timeout 600\\n\";\n\
write(STDERR_FILENO, msg, sizeof(msg) - 1);\n\
_exit(-1);\n}\n") < 0) {
return 1;
}
if (fprintf(fpOut,
"\n#if defined(HITLS_BSL_ERR)\n"
"#include \"bsl_err.h\"\n"
"#endif\n\n") < 0) {
return 1;
}
for (int i = 0; i < g_testFuncCount; i++) {
ret = GenFunctionWrapper(fpOut, &g_testFunc[i]);
if (ret < 0) {
Print("generate function wrapper failed\n");
return 1;
}
}
if (g_fuzzEnd == 1) {
ret = fprintf(fpOut, "#define FREE_FUZZ_TC 1\n\n");
} else {
ret = fprintf(fpOut, "#define FREE_FUZZ_TC 0\n\n");
}
if (ret < 0) {
return 1;
}
return 0;
}
static bool IsSuite(char *buf, uint32_t bufLen)
{
uint32_t beginTagLen = strlen("Begin time:");
uint32_t endTagLen = strlen("End time:");
uint32_t resultTagLen = strlen("Result:");
uint32_t atTagLen = strlen("at:");
if (bufLen >= beginTagLen && strncmp(buf, "Begin time:", beginTagLen) == 0) {
return false;
} else if (bufLen >= endTagLen && strncmp(buf, "End time:", endTagLen) == 0) {
return false;
} else if (bufLen >= resultTagLen && strncmp(buf, "Result:", resultTagLen) == 0) {
return false;
} else if (bufLen >= atTagLen && strncmp(buf, "at:", atTagLen) == 0) {
return false;
}
return true;
}
static int ReadAllLogFile(DIR *logDir, int *totalSuiteCount, FILE *outFile, TestSuiteResult *result, int resultLen)
{
struct dirent *dir = NULL;
int suiteCount = 0;
int cur;
DIR *localLogDir = logDir;
FILE *fpAllLog = OpenFile("result.log", "w+", "%s");
if (fpAllLog == NULL) {
return 1;
}
FILE *fpLog = NULL;
while ((dir = readdir(localLogDir)) != NULL) {
char buf[MAX_LOG_LEN];
uint32_t bufLen = sizeof(buf);
if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0) {
continue;
}
if (strlen(dir->d_name) <= 4 || strlen(dir->d_name) > MAX_FILE_PATH_LEN - 1) {
(void)fclose(fpAllLog);
return 1;
}
fpLog = OpenFile(dir->d_name, "r", LOG_FILE_FORMAT);
if (fpLog == NULL) {
(void)fclose(fpAllLog);
return 1;
}
if (suiteCount >= resultLen) {
Print("Reached maximum suite count\n");
(void)fclose(fpLog);
(void)fclose(fpAllLog);
return 1;
}
if (strlen(dir->d_name) >= MAX_TEST_FUNCTION_NAME) {
Print("Dir's Name is too long\n");
(void)fclose(fpLog);
(void)fclose(fpAllLog);
return 1;
}
strcpy(result[suiteCount].name, dir->d_name);
result[suiteCount].name[strlen(dir->d_name) - 4] = '\0';
result[suiteCount].total = 0;
result[suiteCount].pass = 0;
result[suiteCount].skip = 0;
result[suiteCount].line = 0;
while (ReadLine(fpLog, buf, bufLen, 0, 0) == 0) {
char testCaseName[MAX_TEST_FUNCTION_NAME];
memset(testCaseName, 0, MAX_TEST_FUNCTION_NAME);
if (!IsSuite(buf, strlen(buf))) {
continue;
}
result[suiteCount].total++;
size_t lineLen = strlen(buf);
int end = (int)lineLen - 1;
while (end >= 0 && (buf[end] == '\r' || buf[end] == '\n' || buf[end] == ' ')) {
end--;
}
int dotPos = -1;
for (int i = end; i >= 1; i--) {
if (buf[i] == '.' && buf[i - 1] != '.') {
dotPos = i;
break;
}
}
if (dotPos == -1) {
Print("Read log file %s failed\n", dir->d_name);
(void)fclose(fpLog);
(void)fclose(fpAllLog);
return 1;
}
int nameLen = dotPos - 1;
if (nameLen >= MAX_TEST_FUNCTION_NAME || nameLen < 0) {
Print("TestCaseName is too long\n");
(void)fclose(fpLog);
(void)fclose(fpAllLog);
return 1;
}
if (nameLen >= (int)sizeof(testCaseName)) {
(void)fclose(fpLog);
(void)fclose(fpAllLog);
return 1;
}
memcpy(testCaseName, buf, (size_t)nameLen);
testCaseName[nameLen] = '\0';
cur = dotPos;
while (buf[cur] == '.') {
cur++;
}
if (strncmp(&buf[cur], "pass", strlen("pass")) == 0) {
result[suiteCount].pass++;
result[suiteCount].line++;
(void)fprintf(outFile, PRINT_TESTCASE_LIST_TAG, testCaseName, result[suiteCount].name);
(void)fprintf(fpAllLog, "%s %s\n", testCaseName, "PASS");
} else if (strncmp(&buf[cur], "skip", strlen("skip")) == 0) {
result[suiteCount].skip++;
result[suiteCount].line++;
(void)fprintf(outFile, PRINT_TESTCASE_LIST_TAG, testCaseName, result[suiteCount].name);
(void)fprintf(fpAllLog, "%s %s\n", testCaseName, "SKIP");
} else {
result[suiteCount].line += 3;
(void)fprintf(outFile, PRINT_TESTCASE_LIST_TAG, testCaseName, result[suiteCount].name);
(void)fprintf(fpAllLog, "%s %s\n", testCaseName, "FAIL");
(void)fprintf(outFile, PRINT_FAILURE_TAG);
(void)fprintf(outFile, PRINT_TESTCASE_TAG);
}
}
suiteCount++;
cur = 0;
(void)fclose(fpLog);
}
*totalSuiteCount = suiteCount;
(void)fclose(fpAllLog);
return 0;
}
static int GenResultFile(FILE *in, FILE *out, TestSuiteResult result[MAX_SUITE_COUNT], int testSuiteCount)
{
int totalTests = 0;
int totalPass = 0;
int totalSkip = 0;
if (testSuiteCount >= MAX_SUITE_COUNT) {
Print("suites count too great\n");
return 1;
}
for (int i = 0; i < testSuiteCount; i++) {
totalTests += result[i].total;
totalPass += result[i].pass;
totalSkip += result[i].skip;
}
(void)fprintf(out, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
(void)fprintf(out, "<testsuites tests=\"%d\" failures=\"%d\" disabled=\"%d\" errors=\"0\" ", totalTests,
totalTests - totalPass - totalSkip, totalSkip);
(void)fprintf(out, "timestamp=\"0000-00-00T00:00:00\" time=\"0\" name=\"AllTests\">\n");
for (int i = 0; i < testSuiteCount; i++) {
(void)fprintf(out,
" <testsuite name=\"%s\" tests=\"%d\" skips = \"%d\" failures=\"%d\" ",
result[i].name, result[i].total, result[i].skip,
result[i].total - result[i].pass - result[i].skip);
(void)fprintf(out, "disabled=\"0\" errors=\"0\" time=\"0\">\n");
for (int j = 0; j < result[i].line; j++) {
char buf[MAX_LOG_LEN];
if (fgets(buf, sizeof(buf), in) != NULL) {
(void)fputs(buf, out);
} else {
return 1;
}
}
(void)fprintf(out, PRINT_TESTSUITE_TAG);
}
(void)fprintf(out, PRINT_TESTSUITES_TAG);
return 0;
}
int GenResult(void)
{
int ret;
TestSuiteResult result[MAX_SUITE_COUNT];
int testSuiteCount = 0;
DIR *logDir = NULL;
logDir = opendir(LOG_FILE_DIR);
if (logDir == NULL) {
Print("fail to open log directory\n");
return 1;
}
FILE *fpTmp = NULL;
fpTmp = fopen("tmp.txt", "w+");
if (fpTmp == NULL) {
Print("open tmp.txt failed\n");
(void)closedir(logDir);
return 1;
}
FILE *fpResult = NULL;
fpResult = fopen("result.xml", "w");
if (fpResult == NULL) {
Print("open result.xml failed\n");
(void)closedir(logDir);
(void)fclose(fpTmp);
(void)remove("tmp.txt");
return 1;
}
ret = ReadAllLogFile(logDir, &testSuiteCount, fpTmp, result, sizeof(result));
if (ret != 0) {
Print("read log failed\n");
goto EXIT;
}
rewind(fpTmp);
ret = GenResultFile(fpTmp, fpResult, result, testSuiteCount);
if (ret != 0) {
Print("gen result failed\n");
goto EXIT;
}
EXIT:
(void)closedir(logDir);
(void)fclose(fpTmp);
(void)fclose(fpResult);
(void)remove("tmp.txt");
return ret;
}