Lhogho  0.0.027
Functions | Variables
tester_internal.c File Reference

Functions

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.
static RESULT write_one_line_result (const TCHAR *result, FILE *out_file)
 Writes a line to the expected result 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.
static RESULT get_file_size (const char *file_name, UINT64 *size_ptr)
 Calculate file size.
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_file)
 prints a file to the end of another one
static RESULT compare_strings_output (const TCHAR *test_line, const TCHAR *expected_line)
 Compare result strings.
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.

Variables

int g_first

Function Documentation

RESULT parse_line ( FILE *  input_file,
TCHAR **  parameter_name,
TCHAR **  parameter_optipons 
)
Parameters:
input_filefile to read from
parameter_namename of the parameter readed
parameter_optiponspointer to data assigned to the parameter
Returns:
RESULT value. See error.h for details

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 
)
Parameters:
input_filefile to read from
test_infostruct in which data from parameters will be writen
Returns:
RESULT value. See error.h for details

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 write_one_line_result ( const TCHAR *  result,
FILE *  out_file 
) [static]
Parameters:
resultline to be written
out_filefile to write in
Returns:
RESULT value. See error.h for details

Write a line extracted from test case file to the file containing expected results. Perform some processing on it such as skiping comment symbol.

{
    if (!result || !out_file)
    {
        return ERR_INVALID_ARG;
    }
    if (*result != COMMENT_SYMBOL)
    {
        return SUCCESS_EMPTY;
    }
    
    ++result;   /* skip COMMENT_SYMBOL */

    if (result)
    {
        fwrite(result, m_strlen(result) * sizeof(TCHAR), 1, out_file);
    }
    return SUCCESS_FULL;
}
RESULT extract_expected_results ( FILE *  input_file,
const char *  file_name 
)
Parameters:
input_fileTest case file
file_namename of the file
Returns:
RESULT value. See error.h for details

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 
)
Parameters:
file_nameTest case file name
test_infoOptions for execution
Returns:
execution code as RESULT value

Prepare 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 
)
Parameters:
file_nameTest case file name
test_infoOptions for execution
Returns:
RESULT value. See error.h for details

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 get_file_size ( const char *  file_name,
UINT64 *  size_ptr 
) [static]
Parameters:
file_namename of input file
size_ptrpointer to the file size.
Returns:
RESULT value. See error.h for details

Determine size of file given by file name.

{
    struct stat info;
    if (stat(file_name, &info))
    {
        return ERR_FILE;
    }
    *size_ptr = info.st_size;
    return SUCCESS_FULL;
}
RESULT check_results ( const char *  file_name,
test_case_info  test_info,
UINT32  exec_result 
)
Parameters:
file_namename of tested file
test_infooptions for execution
exec_resultreturn value from execution
Returns:
RESULT value. See error.h for details

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 
)
Parameters:
file_namename of tested file
test_infooptions for execution
Returns:
RESULT value. See error.h for details

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;
}
void clean_up ( const char *  file_name)
Parameters:
file_namename 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 
)
Parameters:
file_namename of file to be printed
output_filefile 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 compare_strings_output ( const TCHAR *  test_line,
const TCHAR *  expected_line 
) [static]
Parameters:
test_lineline produced from test case
expected_lineline expected to be produced

Compare produced from tester data with one expected to be produced. Additional processing on data and sensitiwity of comparisson may be added. Returns success value if lines are "equual" and error if tey are not

{    
    if (!g_parameters.strict_flag)
    {
        TCHAR * test_end, ch_test;
        TCHAR * expect_end, ch_exp;
        int     compare_res;

        while (m_isspace(*expected_line))
            ++expected_line;

        while (m_isspace(*test_line))
            ++test_line;
        
        test_end = (TCHAR*)test_line + m_strlen(test_line) - 1;
        while (test_end > test_line && m_isspace(*test_end))
            --test_end;
        ch_test = test_end[1];
        test_end[1] = 0;


        expect_end = (TCHAR*)expected_line + m_strlen(expected_line) - 1;
        
        while (expect_end > expected_line && m_isspace(*expect_end))
            --expect_end;

        ch_exp = expect_end[1];
        expect_end[1] = 0;

        compare_res = m_strcmp(test_line, expected_line);
        test_end[1] = ch_test;
        expect_end[1] = ch_exp;
        
        return compare_res ? ERR_GENERIC : SUCCESS_FULL;
    }
    else
    {
        return (m_strcmp(test_line, expected_line)==0 ? SUCCESS_FULL : ERR_GENERIC);
    }
}
RESULT file_compare ( const char *  test_file_name,
test_case_info  test_info 
)
Parameters:
test_file_namename of tested file
test_infoparameters for test execution
Returns:
RESULT value. See error.h for details

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)
Parameters:
file_namename of tested file
Returns:
RESULT value. Execuion status

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;
}

Variable Documentation

int g_first

[ HOME | INDEX | ATOMS | VARS | REFERENCE ]
Lhogho Developer's Documentation
Tue Feb 7 2012