Lhogho
0.0.027
|
Data Structures | |
struct | test_case_info_tag |
Defines | |
#define | __INTERNAL_H_8DED3586_3931_4BD5_A578_3B8B6082391C_INCLUDED |
Typedefs | |
typedef RESULT(* | parse_config_attribute_function )(const TCHAR *parameter_name, const TCHAR *parameter_optipons, test_case_info *test_case_params) |
Variables | |
int | g_first |
Basic definitions | |
These macros are used to define basic constants in the code. | |
#define | LOGO_NAME "lhogho" |
#define | TARGET_FILE_EXTENSION "lgo" |
#define | SHELL_FILE_EXTENSION "sh" |
#define | EXPECTED_RESULTS_EXT "expected" |
#define | REAL_RESULTS_EXT "real" |
#define | ERROR_RESULTS_EXT "stderr" |
#define | LTEMP_EXT "ltemp" |
#define | MAX_LINE_LENGTH 2048 |
#define | MAX_NAME_LEN 1024 |
#define | EXPECTED_MEMORY TEXT("{MEM#0:0}") |
#define | MEMORY_CHECK_OPTION "-Zm" |
#define | PARAM_SET_SYMBOL TEXT('=') |
#define | SPACE_ESC_SYMBOL TEXT('\"') |
#define | COMMENT_SYMBOL TEXT(';') |
Config file data types | |
These struct contains data from parameters written into test case file. | |
typedef struct test_case_info_tag | test_case_info |
String functions prototypes | |
int | m_strcmp (const TCHAR *str1, const TCHAR *str2) |
compares two strings | |
TCHAR * | m_strcpy (TCHAR *dest, const TCHAR *src) |
copy string | |
BOOL | m_isspace (TCHAR chr) |
test if char is space | |
RESULT | m_strdup (TCHAR **dest_ptr, const TCHAR *src) |
duplicate string. Allocate memory for destination | |
RESULT | m_strndup (TCHAR **dest_ptr, const TCHAR *src, size_t num_chars) |
duplicate string, but no more than num_chars symbols | |
size_t | m_strlen (const TCHAR *str) |
calculates string length | |
TCHAR * | m_fgets (FILE *file, TCHAR *buffer, size_t buffer_size, size_t *out_size_ptr) |
Read a line from file. | |
void | m_fputs (FILE *file, const TCHAR *buffer) |
prints a line to file | |
void | m_fputs_ascii (FILE *file, const char *buffer) |
prints a line to file, convert it to UNICODE if needed | |
void | m_fputc (FILE *file, TCHAR tchar) |
prints a symbol to file | |
Internal tester helper functions prototypes | |
RESULT | parse_line (FILE *input_file, TCHAR **parameter_name, TCHAR **parameter_optipons) |
Parse a comment line in the test case file. | |
RESULT | extract_args (FILE *input_file, test_case_info *test_info) |
Extracts all argument pairs from test case file. | |
RESULT | extract_expected_results (FILE *input_file, const char *file_name) |
Extract value for expected results from test case file. | |
RESULT | execute_test (const char *file_name, test_case_info test_info) |
Execute a test case. | |
RESULT | compile_test (const char *file_name, test_case_info test_info) |
Compile test case file to executable. | |
RESULT | check_results (const char *file_name, test_case_info test_info, UINT32 exec_result) |
Check results from test case execution. | |
RESULT | import_results (const char *file_name, test_case_info test_info) |
Import results from test execution into test case file. | |
void | clean_up (const char *file_name) |
Clean up any temporary data from test execution. | |
void | print_file (const char *file_name, FILE *output) |
prints a file to the end of another one | |
RESULT | file_compare (const char *test_file_name, test_case_info test_info) |
Compare result file with one expected. | |
RESULT | exec_shell (const char *file_name) |
Execute a shell script with name same as test file name. |
#define LOGO_NAME "lhogho" |
#define TARGET_FILE_EXTENSION "lgo" |
#define SHELL_FILE_EXTENSION "sh" |
#define EXPECTED_RESULTS_EXT "expected" |
#define REAL_RESULTS_EXT "real" |
#define ERROR_RESULTS_EXT "stderr" |
#define LTEMP_EXT "ltemp" |
#define MAX_LINE_LENGTH 2048 |
#define MAX_NAME_LEN 1024 |
#define EXPECTED_MEMORY TEXT("{MEM#0:0}") |
#define MEMORY_CHECK_OPTION "-Zm" |
#define PARAM_SET_SYMBOL TEXT('=') |
#define SPACE_ESC_SYMBOL TEXT('\"') |
#define COMMENT_SYMBOL TEXT(';') |
typedef struct test_case_info_tag test_case_info |
typedef RESULT(* parse_config_attribute_function)(const TCHAR *parameter_name, const TCHAR *parameter_optipons, test_case_info *test_case_params) |
int m_strcmp | ( | const TCHAR * | str1, |
const TCHAR * | str2 | ||
) |
str1 | first string |
str2 | second string |
Comare two strings. Return negative value if first is less than second positive value if first is great than second and zero if strings are equal
{ while (*str1 && *str1 == *str2) { ++str1; ++str2; } return *str1 - *str2; }
TCHAR * m_strcpy | ( | TCHAR * | dest, |
const TCHAR * | src | ||
) |
dest | destination string |
src | source string |
Copy string value to given pointer. User must supply enought memory
{ TCHAR * mem = dest; while (*src) { *dest++ = *src++; } *dest = 0; return mem; }
BOOL m_isspace | ( | TCHAR | chr | ) |
dest_ptr | pointer to destination string |
src | source string |
num_chars | number of characters to copy. |
Copy string value to given pointer, byt no more than num_chars
symbols. Allocates memory for destination. Not copy the 0 byte if source is longer than wanted length
{ *dest_ptr = (TCHAR *)malloc((num_chars + 1) * sizeof(TCHAR)); if (!*dest_ptr) { return ERR_MEMORY; } memcpy(*dest_ptr, src, num_chars * sizeof(TCHAR)); (*dest_ptr)[num_chars] = 0; return SUCCESS_FULL; }
size_t m_strlen | ( | const TCHAR * | str | ) |
str | the string |
Calculates string length in symbols. Works with char and w_char
{ const TCHAR * start = str; while (*str) ++str; return str - start; }
TCHAR * m_fgets | ( | FILE * | file, |
TCHAR * | buffer, | ||
size_t | buffer_size, | ||
size_t * | out_size_ptr | ||
) |
file | file to read from |
buffer | buffer to read in |
buffer_size | size of space in the buffer |
out_size_ptr | size of line readed |
Read characters from given open file until new line symbol is reached or input buffer is full. Returns the count of really readed symbols in parameter and pointer to the buffer. If error occured during read process returns NULL
{ TCHAR c = 0; size_t pos = 0; if (!file || !buffer || !buffer_size || !out_size_ptr) { LOG_ERROR("Invalid args supplied to m_fgets"); if (out_size_ptr) { *out_size_ptr = 0; } return NULL; } while (pos < buffer_size - 1) { if (!fread(&c, sizeof(TCHAR), 1, file)) { break; } buffer[pos++] = c; if (c == TEXT('\r') || c == TEXT('\n')) { TCHAR c1; size_t readed; if ((readed = fread(&c1, sizeof(TCHAR), 1, file)) && (c1 == TEXT('\r') || c1 == TEXT('\n')) && c1 != c) { buffer[pos++] = c1; } else { if (readed) { fseek(file, -1l, SEEK_CUR); } } break; } } buffer[pos] = 0; *out_size_ptr = pos; return pos ? buffer : NULL; }
file | file to write in |
buffer | string to write |
Writes a line to the file. Buffer must be a valid nul-terminated string
{ size_t len = m_strlen(buffer); fwrite(buffer, sizeof(TCHAR), len, file); }
void m_fputs_ascii | ( | FILE * | file, |
const char * | buffer | ||
) |
file | file to write in |
buffer | string to write |
Writes a line to the file. If program works in unicode mode the string is converted from ASCII to unicode.
{ char * buf = (char *)buffer; size_t len = strlen(buffer) * sizeof(TCHAR); #if defined(UNICODE) buf = (char*)malloc(len); while (*buffer) *buf++ = *buffer++, *buf++ = 0; #endif fwrite(buf, sizeof(TCHAR), len, file); #if defined(UNICODE) free(buf); #endif }
file | file to write in |
tchar | symbol to write |
Writes a symbol to file.
{ #if defined (UNICODE) putwc(tchar, file); #else putc(tchar, file); #endif }
RESULT parse_line | ( | FILE * | input_file, |
TCHAR ** | parameter_name, | ||
TCHAR ** | parameter_optipons | ||
) |
input_file | file to read from |
parameter_name | name of the parameter readed |
parameter_optipons | pointer to data assigned to the parameter |
Read a comment line from test case file. If line describes valid parameter-value pair assignes name of parameter to parameter_name
and option value to parameter_optipons
Allocates memory for them. If line is empty return SUCCESS_EMPTY
value If other error occurs return some error value.
{ TCHAR buffer[MAX_LINE_LENGTH]; TCHAR * str, *start, *end; size_t read_size; m_fgets(input_file, buffer, MAX_LINE_LENGTH, &read_size); if (!read_size) { return SUCCESS_EMPTY; } str = buffer; while (*str && m_isspace(*str)) { ++str; } if (!*str) { return SUCCESS_EMPTY; } // Skiping shell comments if (str[0] == '#' && str[1] == '!' && g_first) { g_first = 0; return parse_line(input_file, parameter_name, parameter_optipons); } if (*str != COMMENT_SYMBOL) { LOG_ERROR("parse_line - no comment line"); return ERR_GENERIC; } while (*str == COMMENT_SYMBOL || m_isspace(*str)) { ++str; } start = str; while (*str && *str != PARAM_SET_SYMBOL) { ++str; } if (*str) { end = str; --str; while(str > start && m_isspace(*str)) --str; if (str == start) { LOG_ERROR("parse_line - no param name"); return ERR_GENERIC; } if (*str != PARAM_SET_SYMBOL) ++str; *parameter_name = (TCHAR*)malloc((str - start + 1) * sizeof(TCHAR)); str[0] = 0; m_strcpy(*parameter_name, start); } else { LOG_ERROR("parse_line - no value specified"); return SUCCESS_EMPTY; } str = end+1; while (*str && m_isspace(*str)) { ++str; } m_strdup(parameter_optipons, str); return SUCCESS_FULL; }
RESULT extract_args | ( | FILE * | input_file, |
test_case_info * | test_info | ||
) |
input_file | file to read from |
test_info | struct in which data from parameters will be writen |
Reads comment lines from the source file until empty is found For each extracts data and call all registered parsers. Each of them is responsible to process parameter or return ERR_INVALID_ARG
if doesn't recognise the param name
{ TCHAR * test_name = NULL; TCHAR * test_options = NULL; RESULT res; int i; g_first = 1; while ((res = parse_line(input_file, &test_name, &test_options)) != SUCCESS_EMPTY) { if (IS_ERROR(res)) { LOG_ERROR("Couldn't read parameter from input file"); break; } for (i = 0; i < PARSERS_COUNT; ++i) { if (g_parsers[i]) { res = g_parsers[i](test_name, test_options, test_info); if (IS_ERROR(res) && res != ERR_INVALID_ARG) { break; } } } free (test_name); free (test_options); res = SUCCESS_FULL; } return IS_ERROR(res) ? res : SUCCESS_FULL; }
RESULT extract_expected_results | ( | FILE * | input_file, |
const char * | file_name | ||
) |
input_file | Test case file |
file_name | name of the file |
Read lines with expected results from test case file until empty found. Write them after corresponding processment to the file with name similar to file_name
but with specified suffix.
{ TCHAR buffer [MAX_LINE_LENGTH]; TCHAR * str; size_t real_read_size; RESULT res = SUCCESS_FULL; char new_file_name [MAX_LINE_LENGTH]; FILE * test_file = NULL; strcpy(new_file_name, file_name); strcat(new_file_name, "."EXPECTED_RESULTS_EXT); if (!(test_file = fopen(new_file_name, "wb"))) { return ERR_FILE; } do { str = m_fgets(input_file, buffer, MAX_LINE_LENGTH, &real_read_size); while (str && *str && m_isspace(*str)) { ++str; } res = write_one_line_result(str, test_file); }while (res == SUCCESS_FULL); fclose(test_file); return IS_ERROR(res) ? res : SUCCESS_FULL; }
RESULT execute_test | ( | const char * | file_name, |
test_case_info | test_info | ||
) |
file_name | Test case file name |
test_info | Options for execution |
RESULT
valuePrepare shell comand line calling tested application and execute it. Depending on testing mode could perform different actions. Collect stdout output and return execution success code as SUCCESS result
{ char cmd_buffer[MAX_LINE_LENGTH] = ""; int ret; #if defined(__WIN32__) && defined (__GNUC__) // If executed in Cygwin there is problem with system primitive // 'cause system is calling 'cmd' , not 'bash' strcpy(cmd_buffer, "bash -c \""); #endif if ((g_parameters.tester_mode & MODE_TEST) || (g_parameters.tester_mode & MODE_BUILD) ) { /* will compile a source */ if (g_parameters.compiler_name) { strcat(cmd_buffer, g_parameters.compiler_name); } else { strcat(cmd_buffer, LOGO_NAME); } strcat(cmd_buffer, " "); } else { /* will execute precompiled program */ char * end = (char *)strrchr(file_name, '.'); if (end) *end = '\0'; strcpy(cmd_buffer, file_name); if (end) *end = '.'; } if ((g_parameters.tester_mode & MODE_TEST) || (g_parameters.tester_mode & MODE_EXECUTE)) { strcat(cmd_buffer, MEMORY_CHECK_OPTION); strcat(cmd_buffer, " "); } if (g_parameters.global_params) { strcat(cmd_buffer, g_parameters.global_params); strcat(cmd_buffer, " "); } if (test_info.command_line_param) { strcat(cmd_buffer, test_info.command_line_param); strcat(cmd_buffer, " "); } if ((g_parameters.tester_mode & MODE_TEST) || (g_parameters.tester_mode & MODE_BUILD) ) { strcat(cmd_buffer, file_name); } strcat(cmd_buffer, " 1> "); strcat(cmd_buffer, file_name); strcat(cmd_buffer, "."REAL_RESULTS_EXT); strcat(cmd_buffer, " 2> "); strcat(cmd_buffer, file_name); strcat(cmd_buffer, "."ERROR_RESULTS_EXT); #if defined(__WIN32__) && defined (__GNUC__) strcat(cmd_buffer, "\""); #endif ret = system(cmd_buffer); if (ret == -1) { LOG_ERROR("execution failed"); return ERR_GENERIC; } return MAKE_SUCCESS(ret); }
RESULT compile_test | ( | const char * | file_name, |
test_case_info | test_info | ||
) |
file_name | Test case file name |
test_info | Options for execution |
Calls external compiler to compile test file.
{ char cmd_buffer[MAX_LINE_LENGTH]; int ret; if (g_parameters.compiler_name) { strcpy(cmd_buffer, g_parameters.compiler_name); } else { strcpy(cmd_buffer, LOGO_NAME); } strcat(cmd_buffer, " -x "); if (g_parameters.global_params) { strcat(cmd_buffer, g_parameters.global_params); strcat(cmd_buffer, " "); } if (test_info.command_line_param) { strcat(cmd_buffer, test_info.command_line_param); strcat(cmd_buffer, " "); } strcat(cmd_buffer, file_name); if ((ret = system(cmd_buffer)) == -1) { LOG_ERROR("execution failed"); return ERR_GENERIC; } return MAKE_SUCCESS(ret); }
RESULT check_results | ( | const char * | file_name, |
test_case_info | test_info, | ||
UINT32 | exec_result | ||
) |
file_name | name of tested file |
test_info | options for execution |
exec_result | return value from execution |
Checks results from test execution and compare them with expected.
{ BOOL is_success = TRUE; UINT64 size; RESULT res; char par_name[MAX_NAME_LEN]; size_t file_name_len; file_name_len = m_strlen(file_name); strcpy(par_name, file_name); if (0 && exec_result) // No exit code tests now! { if (g_parameters.verbose_flag) { fprintf(g_parameters.output_file, "Error executing test :"); m_fputs(g_parameters.output_file, test_info.test_name ? test_info.test_name : file_name); fprintf(g_parameters.output_file, "Exit code : %u\n", exec_result); } return MAKE_SUCCESS(exec_result); } strcpy(par_name + file_name_len, "."ERROR_RESULTS_EXT); res = get_file_size(par_name, &size); if (IS_ERROR(res)) { LOG_ERROR("get_file_size failed"); return res; } if (size) { if (g_parameters.verbose_flag) { fprintf(g_parameters.output_file, "Executing test "); m_fputs(g_parameters.output_file, test_info.test_name ? test_info.test_name : file_name); fprintf(g_parameters.output_file, " causet output to stderr\n"); print_file(par_name, g_parameters.output_file); } return MAKE_SUCCESS((UINT32)size); } if (res = file_compare(file_name, test_info)) { return res; } if (g_parameters.verbose_flag) { fprintf(g_parameters.output_file, "Executing test "); m_fputs(g_parameters.output_file, test_info.test_name ? test_info.test_name : file_name); fprintf(g_parameters.output_file, " success!\n"); } return SUCCESS_FULL; }
RESULT import_results | ( | const char * | file_name, |
test_case_info | test_info | ||
) |
file_name | name of tested file |
test_info | options for execution |
Import results from test execution into test case file.
{ TCHAR line[MAX_LINE_LENGTH]; size_t real_size; char exp_name[MAX_NAME_LEN]; char temp_name[MAX_NAME_LEN]; FILE * expected_file; FILE * source_file; FILE * temp_file; strcpy(exp_name, file_name); strcat(exp_name, "."REAL_RESULTS_EXT); expected_file = fopen(exp_name, "rb"); if (!expected_file) { LOG_ERROR("Can't open expected file"); return ERR_FILE; } strcpy(temp_name, file_name); strcat(temp_name, "."LTEMP_EXT); temp_file = fopen(temp_name, "wb"); if (!temp_file) { LOG_ERROR("Can't open temp file"); return ERR_FILE; } source_file = fopen(file_name, "rb"); if (!source_file) { LOG_ERROR("Can't open source file"); return ERR_FILE; } fprintf(temp_file, "\n"); while (m_fgets(expected_file, line, MAX_LINE_LENGTH, &real_size)) { if (real_size && real_size < MAX_LINE_LENGTH) { m_fputc(temp_file, COMMENT_SYMBOL); } m_fputs(temp_file, line); } fprintf(temp_file, "\n"); fclose(expected_file); unlink(exp_name); while (m_fgets(source_file, line, MAX_LINE_LENGTH, &real_size)) { m_fputs(temp_file, line); } fclose(temp_file); fclose(source_file); unlink(file_name); return rename(temp_name, file_name) == 0 ? SUCCESS_FULL : ERR_FILE; }
file_name | name of tested file |
Remove any temporary files produced from test execution process
{ char name[MAX_NAME_LEN]; size_t file_name_len; file_name_len = m_strlen(file_name); strcpy(name, file_name); strcpy(name + file_name_len, "."EXPECTED_RESULTS_EXT); unlink(name); strcpy(name + file_name_len, "."REAL_RESULTS_EXT); unlink(name); strcpy(name + file_name_len, "."ERROR_RESULTS_EXT); unlink(name); }
void print_file | ( | const char * | file_name, |
FILE * | output_file | ||
) |
file_name | name of file to be printed |
output_file | file where data will be appended |
Appends contet of input file into end of destination file
{ TCHAR buffer[MAX_LINE_LENGTH]; size_t size; FILE * f = fopen(file_name, "rb"); if (!f) { LOG_ERROR("Open file to print failed"); return; } while(m_fgets(f, buffer, MAX_LINE_LENGTH, &size)) { m_fputs(output_file, buffer); } fclose(f); }
RESULT file_compare | ( | const char * | test_file_name, |
test_case_info | test_info | ||
) |
test_file_name | name of tested file |
test_info | parameters for test execution |
Compare file containing produced from tester data with file containing expected data Returns success value if lines are "equual" and error if tey are not
{ TCHAR expected[MAX_LINE_LENGTH]; TCHAR expected_mem[] = EXPECTED_MEMORY; TCHAR real[MAX_LINE_LENGTH]; size_t real_size, exp_size; char name[MAX_NAME_LEN]; RESULT res = SUCCESS_FULL; int mem_checked = 0; FILE * expected_file; FILE * real_file; strcpy(name, test_file_name); strcat(name, "."EXPECTED_RESULTS_EXT); expected_file = fopen(name, "rb"); if (!expected_file) { LOG_ERROR("Can't open expected file"); return ERR_FILE; } strcpy(name, test_file_name); strcat(name, "."REAL_RESULTS_EXT); real_file = fopen(name, "rb"); if (!real_file) { LOG_ERROR("Can't open real file"); return ERR_FILE; } while (m_fgets(real_file, real, MAX_LINE_LENGTH, &real_size)) { if (!m_fgets(expected_file, expected, MAX_LINE_LENGTH, &exp_size)) { if (!mem_checked) { mem_checked = 1; if (SUCCESS_FULL == compare_strings_output(real, expected_mem)) { continue; } } if (g_parameters.verbose_flag) { fprintf(g_parameters.output_file, "Test %s failed. Extra line in output: \n%s\n", test_info.test_name ? test_info.test_name : test_file_name, real); } else { fprintf(g_parameters.output_file, "Test failed\n"); } res = ERR_GENERIC; break; } if (IS_ERROR(compare_strings_output(real, expected))) { if (g_parameters.verbose_flag) { fprintf(g_parameters.output_file, "Test %s failed. Unexpected line in output: \n\"%s\"\n" "\tExpected\n\"%s\"\n", test_info.test_name ? test_info.test_name : test_file_name, real, expected); } else { fprintf(g_parameters.output_file, "Test failed\n"); } res = ERR_GENERIC; break; } } if (m_fgets(expected_file, expected, MAX_LINE_LENGTH, &exp_size)) { int i = 0; if (expected[i]) { if (g_parameters.verbose_flag) { fprintf(g_parameters.output_file, "Test %s failed. Extra line in output: \n%s\n", test_info.test_name ? test_info.test_name : test_file_name, real); } else { fprintf(g_parameters.output_file, "Test failed\n"); } res = ERR_GENERIC; } } if (!mem_checked) { if (g_parameters.verbose_flag) { fprintf(g_parameters.output_file, "Test %s failed. No memory check performed!\n", test_info.test_name ? test_info.test_name : test_file_name); } else { fprintf(g_parameters.output_file, "Test failed\n"); } res = ERR_GENERIC; } fclose(real_file); fclose(expected_file); return res; }
RESULT exec_shell | ( | const char * | file_name | ) |
file_name | name of tested file |
Try to execute shell script with name same as input file if any. If no script exist return SUCCESS_FILE else return SUCESS_FULL on successfull execution of ERR_GENERIC on error.
{ RESULT res = SUCCESS_FILE; FILE * test_file; char sh_name[512]; char command[512] = "bash -c "; size_t len; int ret_code; char * dot_pos = strrchr(file_name, '.'); // Prepare shell file name if (dot_pos && dot_pos != file_name) { len = dot_pos - file_name; } else { len = strlen(file_name); } strncpy(sh_name, file_name, len); sh_name[len++] = '.'; strcpy(sh_name+len, SHELL_FILE_EXTENSION); // Try to open file test_file = fopen(sh_name, "r"); if (!test_file) { return SUCCESS_FILE; } fclose(test_file); ret_code = system(strcat(command, sh_name)); if (g_parameters.verbose_flag) { fprintf(stderr, "execution:%s-> %d\n", sh_name, ret_code); } if (ret_code == -1) // execution failed! { LOG_ERROR("execution failed"); return SUCCESS_FILE; } if (ret_code == 0) { ++g_parameters.num_passed; return SUCCESS_FULL; } ++g_parameters.num_failed; return ERR_GENERIC; }
int g_first |