cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

harness_argparser.c (10306B)


      1/* See COPYING.txt for the full license governing this code. */
      2/**
      3 * \file harness_argparser.c
      4 *
      5 * Source file for functions to parse arguments to the test harness.
      6 */
      7
      8#include <SDL_test.h>
      9#include <stdio.h>
     10#include <string.h>
     11
     12#include "SDL_visualtest_harness_argparser.h"
     13#include "SDL_visualtest_rwhelper.h"
     14
     15/** Maximum length of one line in the config file */
     16#define MAX_CONFIG_LINE_LEN 400
     17/** Default value for the timeout after which the SUT is forcefully killed */
     18#define DEFAULT_SUT_TIMEOUT (60 * 1000)
     19
     20/* String compare s1 and s2 ignoring leading hyphens */
     21static int
     22StrCaseCmpIgnoreHyphen(char* s1, char* s2)
     23{
     24    /* treat NULL pointer as empty strings */
     25    if(!s1)
     26        s1 = "";
     27    if(!s2)
     28        s2 = "";
     29
     30    while(*s1 == '-')
     31        s1++;
     32    while(*s2 == '-')
     33        s2++;
     34
     35    return SDL_strcasecmp(s1, s2);
     36}
     37
     38/* parser an argument, updates the state object and returns the number of
     39   arguments processed; returns -1 on failure */
     40static int
     41ParseArg(char** argv, int index, SDLVisualTest_HarnessState* state)
     42{
     43    if(!argv || !argv[index] || !state)
     44        return 0;
     45
     46    if(StrCaseCmpIgnoreHyphen("sutapp", argv[index]) == 0)
     47    {
     48        index++;
     49        if(!argv[index])
     50        {
     51            SDLTest_LogError("Arguments parsing error: Invalid argument for sutapp.");
     52            return -1;
     53        }
     54        SDL_strlcpy(state->sutapp, argv[index], MAX_PATH_LEN);
     55        SDLTest_Log("SUT Application: %s", state->sutapp);
     56        return 2;
     57    }
     58    else if(StrCaseCmpIgnoreHyphen("output-dir", argv[index]) == 0)
     59    {
     60        index++;
     61        if(!argv[index])
     62        {
     63            SDLTest_LogError("Arguments parsing error: Invalid argument for output-dir.");
     64            return -1;
     65        }
     66        SDL_strlcpy(state->output_dir, argv[index], MAX_PATH_LEN);
     67        SDLTest_Log("Screenshot Output Directory: %s", state->output_dir);
     68        return 2;
     69    }
     70    else if(StrCaseCmpIgnoreHyphen("verify-dir", argv[index]) == 0)
     71    {
     72        index++;
     73        if(!argv[index])
     74        {
     75            SDLTest_LogError("Arguments parsing error: Invalid argument for verify-dir.");
     76            return -1;
     77        }
     78        SDL_strlcpy(state->verify_dir, argv[index], MAX_PATH_LEN);
     79        SDLTest_Log("Screenshot Verification Directory: %s", state->verify_dir);
     80        return 2;
     81    }
     82    else if(StrCaseCmpIgnoreHyphen("sutargs", argv[index]) == 0)
     83    {
     84        index++;
     85        if(!argv[index])
     86        {
     87            SDLTest_LogError("Arguments parsing error: Invalid argument for sutargs.");
     88            return -1;
     89        }
     90        SDL_strlcpy(state->sutargs, argv[index], MAX_SUT_ARGS_LEN);
     91        SDLTest_Log("SUT Arguments: %s", state->sutargs);
     92        return 2;
     93    }
     94    else if(StrCaseCmpIgnoreHyphen("timeout", argv[index]) == 0)
     95    {
     96        int hr, min, sec;
     97        index++;
     98        if(!argv[index] || SDL_sscanf(argv[index], "%d:%d:%d", &hr, &min, &sec) != 3)
     99        {
    100            SDLTest_LogError("Arguments parsing error: Invalid argument for timeout.");
    101            return -1;
    102        }
    103        state->timeout = (((hr * 60) + min) * 60 + sec) * 1000;
    104        SDLTest_Log("Maximum Timeout for each SUT run: %d milliseconds",
    105                    state->timeout);
    106        return 2;
    107    }
    108    else if(StrCaseCmpIgnoreHyphen("parameter-config", argv[index]) == 0)
    109    {
    110        index++;
    111        if(!argv[index])
    112        {
    113            SDLTest_LogError("Arguments parsing error: Invalid argument for parameter-config.");
    114            return -1;
    115        }
    116        SDLTest_Log("SUT Parameters file: %s", argv[index]);
    117        SDLVisualTest_FreeSUTConfig(&state->sut_config);
    118        if(!SDLVisualTest_ParseSUTConfig(argv[index], &state->sut_config))
    119        {
    120            SDLTest_LogError("Failed to parse SUT parameters file");
    121            return -1;
    122        }
    123        return 2;
    124    }
    125    else if(StrCaseCmpIgnoreHyphen("variator", argv[index]) == 0)
    126    {
    127        index++;
    128        if(!argv[index])
    129        {
    130            SDLTest_LogError("Arguments parsing error: Invalid argument for variator.");
    131            return -1;
    132        }
    133        SDLTest_Log("Variator: %s", argv[index]);
    134        if(SDL_strcasecmp("exhaustive", argv[index]) == 0)
    135            state->variator_type = SDL_VARIATOR_EXHAUSTIVE;
    136        else if(SDL_strcasecmp("random", argv[index]) == 0)
    137            state->variator_type = SDL_VARIATOR_RANDOM;
    138        else
    139        {
    140            SDLTest_LogError("Arguments parsing error: Invalid variator name.");
    141            return -1;
    142        }
    143        return 2;
    144    }
    145    else if(StrCaseCmpIgnoreHyphen("num-variations", argv[index]) == 0)
    146    {
    147        index++;
    148        if(!argv[index])
    149        {
    150            SDLTest_LogError("Arguments parsing error: Invalid argument for num-variations.");
    151            return -1;
    152        }
    153        state->num_variations = SDL_atoi(argv[index]);
    154        SDLTest_Log("Number of variations to run: %d", state->num_variations);
    155        if(state->num_variations <= 0)
    156        {
    157            SDLTest_LogError("Arguments parsing error: num-variations must be positive.");
    158            return -1;
    159        }
    160        return 2;
    161    }
    162    else if(StrCaseCmpIgnoreHyphen("no-launch", argv[index]) == 0)
    163    {
    164        state->no_launch = SDL_TRUE;
    165        SDLTest_Log("SUT will not be launched.");
    166        return 1;
    167    }
    168    else if(StrCaseCmpIgnoreHyphen("action-config", argv[index]) == 0)
    169    {
    170        index++;
    171        if(!argv[index])
    172        {
    173            SDLTest_LogError("Arguments parsing error: invalid argument for action-config");
    174            return -1;
    175        }
    176        SDLTest_Log("Action Config file: %s", argv[index]);
    177        SDLVisualTest_EmptyActionQueue(&state->action_queue);
    178        if(!SDLVisualTest_ParseActionConfig(argv[index], &state->action_queue))
    179        {
    180            SDLTest_LogError("SDLVisualTest_ParseActionConfig() failed");
    181            return -1;
    182        }
    183        return 2;
    184    }
    185    else if(StrCaseCmpIgnoreHyphen("config", argv[index]) == 0)
    186    {
    187        index++;
    188        if(!argv[index])
    189        {
    190            SDLTest_LogError("Arguments parsing error: invalid argument for config");
    191            return -1;
    192        }
    193
    194        /* do nothing, this option has already been handled */
    195        return 2;
    196    }
    197    return 0;
    198}
    199
    200/* TODO: Trailing/leading spaces and spaces between equals sign not supported. */
    201static int
    202ParseConfig(char* file, SDLVisualTest_HarnessState* state)
    203{
    204    SDL_RWops* rw;
    205    SDLVisualTest_RWHelperBuffer buffer;
    206    char line[MAX_CONFIG_LINE_LEN];
    207
    208    rw = SDL_RWFromFile(file, "r");
    209    if(!rw)
    210    {
    211        SDLTest_LogError("SDL_RWFromFile() failed");
    212        return 0;
    213    }
    214
    215    SDLVisualTest_RWHelperResetBuffer(&buffer);
    216    while(SDLVisualTest_RWHelperReadLine(rw, line, MAX_CONFIG_LINE_LEN,
    217                                         &buffer, '#'))
    218    {
    219        char** argv;
    220        int i, num_params;
    221
    222        /* count number of parameters and replace the trailing newline with 0 */
    223        num_params = 1;
    224        for(i = 0; line[i]; i++)
    225        {
    226            if(line[i] == '=')
    227            {
    228                num_params = 2;
    229                break;
    230            }
    231        }
    232
    233        /* populate argv */
    234        argv = (char**)SDL_malloc((num_params + 1) * sizeof(char*));
    235        if(!argv)
    236        {
    237            SDLTest_LogError("malloc() failed.");
    238            SDL_RWclose(rw);
    239            return 0;
    240        }
    241
    242        argv[num_params] = NULL;
    243        for(i = 0; i < num_params; i++)
    244        {
    245            argv[i] = strtok(i == 0 ? line : NULL, "=");
    246        }
    247
    248        if(ParseArg(argv, 0, state) == -1)
    249        {
    250            SDLTest_LogError("ParseArg() failed");
    251            SDL_free(argv);
    252            SDL_RWclose(rw);
    253            return 0;
    254        }
    255        SDL_free(argv);
    256    }
    257    SDL_RWclose(rw);
    258
    259    if(!state->sutapp[0])
    260        return 0;
    261    return 1;
    262}
    263
    264int
    265SDLVisualTest_ParseHarnessArgs(char** argv, SDLVisualTest_HarnessState* state)
    266{
    267    int i;
    268
    269    SDLTest_Log("Parsing commandline arguments..");
    270
    271    if(!argv)
    272    {
    273        SDLTest_LogError("argv is NULL");
    274        return 0;
    275    }
    276    if(!state)
    277    {
    278        SDLTest_LogError("state is NULL");
    279        return 0;
    280    }
    281
    282    /* initialize the state object */
    283    state->sutargs[0] = '\0';
    284    state->sutapp[0] = '\0';
    285    state->output_dir[0] = '\0';
    286    state->verify_dir[0] = '\0';
    287    state->timeout = DEFAULT_SUT_TIMEOUT;
    288    SDL_memset(&state->sut_config, 0, sizeof(SDLVisualTest_SUTConfig));
    289    SDL_memset(&state->action_queue, 0, sizeof(SDLVisualTest_ActionQueue));
    290    state->variator_type = SDL_VARIATOR_RANDOM;
    291    state->num_variations = -1;
    292    state->no_launch = SDL_FALSE;
    293
    294    /* parse config file if passed */
    295    for(i = 0; argv[i]; i++)
    296    {
    297        if(StrCaseCmpIgnoreHyphen("config", argv[i]) == 0)
    298        {
    299            if(!argv[i + 1])
    300            {
    301                SDLTest_Log("Arguments parsing error: invalid argument for config.");
    302                return 0;
    303            }
    304            if(!ParseConfig(argv[i + 1], state))
    305            {
    306                SDLTest_LogError("ParseConfig() failed");
    307                return 0;
    308            }
    309        }
    310    }
    311
    312    /* parse the arguments */
    313    for(i = 0; argv[i];)
    314    {
    315        int consumed = ParseArg(argv, i, state);
    316        if(consumed == -1 || consumed == 0)
    317        {
    318            SDLTest_LogError("ParseArg() failed");
    319            return 0;
    320        }
    321        i += consumed;
    322    }
    323
    324    if(state->variator_type == SDL_VARIATOR_RANDOM && state->num_variations == -1)
    325        state->num_variations = 1;
    326
    327    /* check to see if required options have been passed */
    328    if(!state->sutapp[0])
    329    {
    330        SDLTest_LogError("sutapp must be passed.");
    331        return 0;
    332    }
    333    if(!state->sutargs[0] && !state->sut_config.options)
    334    {
    335        SDLTest_LogError("Either sutargs or parameter-config must be passed.");
    336        return 0;
    337    }
    338    if(!state->output_dir[0])
    339    {
    340        SDL_strlcpy(state->output_dir, "./output", MAX_PATH_LEN);
    341    }
    342    if(!state->verify_dir[0])
    343    {
    344        SDL_strlcpy(state->verify_dir, "./verify", MAX_PATH_LEN);
    345    }
    346
    347    return 1;
    348}
    349
    350void
    351SDLVisualTest_FreeHarnessState(SDLVisualTest_HarnessState* state)
    352{
    353    if(state)
    354    {
    355        SDLVisualTest_EmptyActionQueue(&state->action_queue);
    356        SDLVisualTest_FreeSUTConfig(&state->sut_config);
    357    }
    358}