visualtest/src/harness_argparser.c
changeset 7924 fcb86d323770
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/visualtest/src/harness_argparser.c	Sun Nov 10 00:32:23 2013 -0500
     1.3 @@ -0,0 +1,358 @@
     1.4 +/* See COPYING.txt for the full license governing this code. */
     1.5 +/**
     1.6 + * \file harness_argparser.c
     1.7 + *
     1.8 + * Source file for functions to parse arguments to the test harness.
     1.9 + */
    1.10 +
    1.11 +#include <SDL_test.h>
    1.12 +#include <stdio.h>
    1.13 +#include <string.h>
    1.14 +
    1.15 +#include "SDL_visualtest_harness_argparser.h"
    1.16 +#include "SDL_visualtest_rwhelper.h"
    1.17 +
    1.18 +/** Maximum length of one line in the config file */
    1.19 +#define MAX_CONFIG_LINE_LEN 400
    1.20 +/** Default value for the timeout after which the SUT is forcefully killed */
    1.21 +#define DEFAULT_SUT_TIMEOUT (60 * 1000)
    1.22 +
    1.23 +/* String compare s1 and s2 ignoring leading hyphens */
    1.24 +static int
    1.25 +StrCaseCmpIgnoreHyphen(char* s1, char* s2)
    1.26 +{
    1.27 +    /* treat NULL pointer as empty strings */
    1.28 +    if(!s1)
    1.29 +        s1 = "";
    1.30 +    if(!s2)
    1.31 +        s2 = "";
    1.32 +
    1.33 +    while(*s1 == '-')
    1.34 +        s1++;
    1.35 +    while(*s2 == '-')
    1.36 +        s2++;
    1.37 +
    1.38 +    return SDL_strcasecmp(s1, s2);
    1.39 +}
    1.40 +
    1.41 +/* parser an argument, updates the state object and returns the number of
    1.42 +   arguments processed; returns -1 on failure */
    1.43 +static int
    1.44 +ParseArg(char** argv, int index, SDLVisualTest_HarnessState* state)
    1.45 +{
    1.46 +    if(!argv || !argv[index] || !state)
    1.47 +        return 0;
    1.48 +
    1.49 +    if(StrCaseCmpIgnoreHyphen("sutapp", argv[index]) == 0)
    1.50 +    {
    1.51 +        index++;
    1.52 +        if(!argv[index])
    1.53 +        {
    1.54 +            SDLTest_LogError("Arguments parsing error: Invalid argument for sutapp.");
    1.55 +            return -1;
    1.56 +        }
    1.57 +        SDL_strlcpy(state->sutapp, argv[index], MAX_PATH_LEN);
    1.58 +        SDLTest_Log("SUT Application: %s", state->sutapp);
    1.59 +        return 2;
    1.60 +    }
    1.61 +    else if(StrCaseCmpIgnoreHyphen("output-dir", argv[index]) == 0)
    1.62 +    {
    1.63 +        index++;
    1.64 +        if(!argv[index])
    1.65 +        {
    1.66 +            SDLTest_LogError("Arguments parsing error: Invalid argument for output-dir.");
    1.67 +            return -1;
    1.68 +        }
    1.69 +        SDL_strlcpy(state->output_dir, argv[index], MAX_PATH_LEN);
    1.70 +        SDLTest_Log("Screenshot Output Directory: %s", state->output_dir);
    1.71 +        return 2;
    1.72 +    }
    1.73 +    else if(StrCaseCmpIgnoreHyphen("verify-dir", argv[index]) == 0)
    1.74 +    {
    1.75 +        index++;
    1.76 +        if(!argv[index])
    1.77 +        {
    1.78 +            SDLTest_LogError("Arguments parsing error: Invalid argument for verify-dir.");
    1.79 +            return -1;
    1.80 +        }
    1.81 +        SDL_strlcpy(state->verify_dir, argv[index], MAX_PATH_LEN);
    1.82 +        SDLTest_Log("Screenshot Verification Directory: %s", state->verify_dir);
    1.83 +        return 2;
    1.84 +    }
    1.85 +    else if(StrCaseCmpIgnoreHyphen("sutargs", argv[index]) == 0)
    1.86 +    {
    1.87 +        index++;
    1.88 +        if(!argv[index])
    1.89 +        {
    1.90 +            SDLTest_LogError("Arguments parsing error: Invalid argument for sutargs.");
    1.91 +            return -1;
    1.92 +        }
    1.93 +        SDL_strlcpy(state->sutargs, argv[index], MAX_SUT_ARGS_LEN);
    1.94 +        SDLTest_Log("SUT Arguments: %s", state->sutargs);
    1.95 +        return 2;
    1.96 +    }
    1.97 +    else if(StrCaseCmpIgnoreHyphen("timeout", argv[index]) == 0)
    1.98 +    {
    1.99 +        int hr, min, sec;
   1.100 +        index++;
   1.101 +        if(!argv[index] || SDL_sscanf(argv[index], "%d:%d:%d", &hr, &min, &sec) != 3)
   1.102 +        {
   1.103 +            SDLTest_LogError("Arguments parsing error: Invalid argument for timeout.");
   1.104 +            return -1;
   1.105 +        }
   1.106 +        state->timeout = (((hr * 60) + min) * 60 + sec) * 1000;
   1.107 +        SDLTest_Log("Maximum Timeout for each SUT run: %d milliseconds",
   1.108 +                    state->timeout);
   1.109 +        return 2;
   1.110 +    }
   1.111 +    else if(StrCaseCmpIgnoreHyphen("parameter-config", argv[index]) == 0)
   1.112 +    {
   1.113 +        index++;
   1.114 +        if(!argv[index])
   1.115 +        {
   1.116 +            SDLTest_LogError("Arguments parsing error: Invalid argument for parameter-config.");
   1.117 +            return -1;
   1.118 +        }
   1.119 +        SDLTest_Log("SUT Parameters file: %s", argv[index]);
   1.120 +        SDLVisualTest_FreeSUTConfig(&state->sut_config);
   1.121 +        if(!SDLVisualTest_ParseSUTConfig(argv[index], &state->sut_config))
   1.122 +        {
   1.123 +            SDLTest_LogError("Failed to parse SUT parameters file");
   1.124 +            return -1;
   1.125 +        }
   1.126 +        return 2;
   1.127 +    }
   1.128 +    else if(StrCaseCmpIgnoreHyphen("variator", argv[index]) == 0)
   1.129 +    {
   1.130 +        index++;
   1.131 +        if(!argv[index])
   1.132 +        {
   1.133 +            SDLTest_LogError("Arguments parsing error: Invalid argument for variator.");
   1.134 +            return -1;
   1.135 +        }
   1.136 +        SDLTest_Log("Variator: %s", argv[index]);
   1.137 +        if(SDL_strcasecmp("exhaustive", argv[index]) == 0)
   1.138 +            state->variator_type = SDL_VARIATOR_EXHAUSTIVE;
   1.139 +        else if(SDL_strcasecmp("random", argv[index]) == 0)
   1.140 +            state->variator_type = SDL_VARIATOR_RANDOM;
   1.141 +        else
   1.142 +        {
   1.143 +            SDLTest_LogError("Arguments parsing error: Invalid variator name.");
   1.144 +            return -1;
   1.145 +        }
   1.146 +        return 2;
   1.147 +    }
   1.148 +    else if(StrCaseCmpIgnoreHyphen("num-variations", argv[index]) == 0)
   1.149 +    {
   1.150 +        index++;
   1.151 +        if(!argv[index])
   1.152 +        {
   1.153 +            SDLTest_LogError("Arguments parsing error: Invalid argument for num-variations.");
   1.154 +            return -1;
   1.155 +        }
   1.156 +        state->num_variations = SDL_atoi(argv[index]);
   1.157 +        SDLTest_Log("Number of variations to run: %d", state->num_variations);
   1.158 +        if(state->num_variations <= 0)
   1.159 +        {
   1.160 +            SDLTest_LogError("Arguments parsing error: num-variations must be positive.");
   1.161 +            return -1;
   1.162 +        }
   1.163 +        return 2;
   1.164 +    }
   1.165 +    else if(StrCaseCmpIgnoreHyphen("no-launch", argv[index]) == 0)
   1.166 +    {
   1.167 +        state->no_launch = SDL_TRUE;
   1.168 +        SDLTest_Log("SUT will not be launched.");
   1.169 +        return 1;
   1.170 +    }
   1.171 +    else if(StrCaseCmpIgnoreHyphen("action-config", argv[index]) == 0)
   1.172 +    {
   1.173 +        index++;
   1.174 +        if(!argv[index])
   1.175 +        {
   1.176 +            SDLTest_LogError("Arguments parsing error: invalid argument for action-config");
   1.177 +            return -1;
   1.178 +        }
   1.179 +        SDLTest_Log("Action Config file: %s", argv[index]);
   1.180 +        SDLVisualTest_EmptyActionQueue(&state->action_queue);
   1.181 +        if(!SDLVisualTest_ParseActionConfig(argv[index], &state->action_queue))
   1.182 +        {
   1.183 +            SDLTest_LogError("SDLVisualTest_ParseActionConfig() failed");
   1.184 +            return -1;
   1.185 +        }
   1.186 +        return 2;
   1.187 +    }
   1.188 +    else if(StrCaseCmpIgnoreHyphen("config", argv[index]) == 0)
   1.189 +    {
   1.190 +        index++;
   1.191 +        if(!argv[index])
   1.192 +        {
   1.193 +            SDLTest_LogError("Arguments parsing error: invalid argument for config");
   1.194 +            return -1;
   1.195 +        }
   1.196 +
   1.197 +        /* do nothing, this option has already been handled */
   1.198 +        return 2;
   1.199 +    }
   1.200 +    return 0;
   1.201 +}
   1.202 +
   1.203 +/* TODO: Trailing/leading spaces and spaces between equals sign not supported. */
   1.204 +static int
   1.205 +ParseConfig(char* file, SDLVisualTest_HarnessState* state)
   1.206 +{
   1.207 +    SDL_RWops* rw;
   1.208 +    SDLVisualTest_RWHelperBuffer buffer;
   1.209 +    char line[MAX_CONFIG_LINE_LEN];
   1.210 +
   1.211 +    rw = SDL_RWFromFile(file, "r");
   1.212 +    if(!rw)
   1.213 +    {
   1.214 +        SDLTest_LogError("SDL_RWFromFile() failed");
   1.215 +        return 0;
   1.216 +    }
   1.217 +
   1.218 +    SDLVisualTest_RWHelperResetBuffer(&buffer);
   1.219 +    while(SDLVisualTest_RWHelperReadLine(rw, line, MAX_CONFIG_LINE_LEN,
   1.220 +                                         &buffer, '#'))
   1.221 +    {
   1.222 +        char** argv;
   1.223 +        int i, num_params;
   1.224 +
   1.225 +        /* count number of parameters and replace the trailing newline with 0 */
   1.226 +        num_params = 1;
   1.227 +        for(i = 0; line[i]; i++)
   1.228 +        {
   1.229 +            if(line[i] == '=')
   1.230 +            {
   1.231 +                num_params = 2;
   1.232 +                break;
   1.233 +            }
   1.234 +        }
   1.235 +
   1.236 +        /* populate argv */
   1.237 +        argv = (char**)SDL_malloc((num_params + 1) * sizeof(char*));
   1.238 +        if(!argv)
   1.239 +        {
   1.240 +            SDLTest_LogError("malloc() failed.");
   1.241 +            SDL_RWclose(rw);
   1.242 +            return 0;
   1.243 +        }
   1.244 +
   1.245 +        argv[num_params] = NULL;
   1.246 +        for(i = 0; i < num_params; i++)
   1.247 +        {
   1.248 +            argv[i] = strtok(i == 0 ? line : NULL, "=");
   1.249 +        }
   1.250 +
   1.251 +        if(ParseArg(argv, 0, state) == -1)
   1.252 +        {
   1.253 +            SDLTest_LogError("ParseArg() failed");
   1.254 +            SDL_free(argv);
   1.255 +            SDL_RWclose(rw);
   1.256 +            return 0;
   1.257 +        }
   1.258 +        SDL_free(argv);
   1.259 +    }
   1.260 +    SDL_RWclose(rw);
   1.261 +
   1.262 +    if(!state->sutapp[0])
   1.263 +        return 0;
   1.264 +    return 1;
   1.265 +}
   1.266 +
   1.267 +int
   1.268 +SDLVisualTest_ParseHarnessArgs(char** argv, SDLVisualTest_HarnessState* state)
   1.269 +{
   1.270 +    int i;
   1.271 +
   1.272 +    SDLTest_Log("Parsing commandline arguments..");
   1.273 +
   1.274 +    if(!argv)
   1.275 +    {
   1.276 +        SDLTest_LogError("argv is NULL");
   1.277 +        return 0;
   1.278 +    }
   1.279 +    if(!state)
   1.280 +    {
   1.281 +        SDLTest_LogError("state is NULL");
   1.282 +        return 0;
   1.283 +    }
   1.284 +
   1.285 +    /* initialize the state object */
   1.286 +    state->sutargs[0] = '\0';
   1.287 +    state->sutapp[0] = '\0';
   1.288 +    state->output_dir[0] = '\0';
   1.289 +    state->verify_dir[0] = '\0';
   1.290 +    state->timeout = DEFAULT_SUT_TIMEOUT;
   1.291 +    SDL_memset(&state->sut_config, 0, sizeof(SDLVisualTest_SUTConfig));
   1.292 +    SDL_memset(&state->action_queue, 0, sizeof(SDLVisualTest_ActionQueue));
   1.293 +    state->variator_type = SDL_VARIATOR_RANDOM;
   1.294 +    state->num_variations = -1;
   1.295 +    state->no_launch = SDL_FALSE;
   1.296 +
   1.297 +    /* parse config file if passed */
   1.298 +    for(i = 0; argv[i]; i++)
   1.299 +    {
   1.300 +        if(StrCaseCmpIgnoreHyphen("config", argv[i]) == 0)
   1.301 +        {
   1.302 +            if(!argv[i + 1])
   1.303 +            {
   1.304 +                SDLTest_Log("Arguments parsing error: invalid argument for config.");
   1.305 +                return 0;
   1.306 +            }
   1.307 +            if(!ParseConfig(argv[i + 1], state))
   1.308 +            {
   1.309 +                SDLTest_LogError("ParseConfig() failed");
   1.310 +                return 0;
   1.311 +            }
   1.312 +        }
   1.313 +    }
   1.314 +
   1.315 +    /* parse the arguments */
   1.316 +    for(i = 0; argv[i];)
   1.317 +    {
   1.318 +        int consumed = ParseArg(argv, i, state);
   1.319 +        if(consumed == -1 || consumed == 0)
   1.320 +        {
   1.321 +            SDLTest_LogError("ParseArg() failed");
   1.322 +            return 0;
   1.323 +        }
   1.324 +        i += consumed;
   1.325 +    }
   1.326 +
   1.327 +    if(state->variator_type == SDL_VARIATOR_RANDOM && state->num_variations == -1)
   1.328 +        state->num_variations = 1;
   1.329 +
   1.330 +    /* check to see if required options have been passed */
   1.331 +    if(!state->sutapp[0])
   1.332 +    {
   1.333 +        SDLTest_LogError("sutapp must be passed.");
   1.334 +        return 0;
   1.335 +    }
   1.336 +    if(!state->sutargs[0] && !state->sut_config.options)
   1.337 +    {
   1.338 +        SDLTest_LogError("Either sutargs or parameter-config must be passed.");
   1.339 +        return 0;
   1.340 +    }
   1.341 +    if(!state->output_dir[0])
   1.342 +    {
   1.343 +        SDL_strlcpy(state->output_dir, "./output", MAX_PATH_LEN);
   1.344 +    }
   1.345 +    if(!state->verify_dir[0])
   1.346 +    {
   1.347 +        SDL_strlcpy(state->verify_dir, "./verify", MAX_PATH_LEN);
   1.348 +    }
   1.349 +
   1.350 +    return 1;
   1.351 +}
   1.352 +
   1.353 +void
   1.354 +SDLVisualTest_FreeHarnessState(SDLVisualTest_HarnessState* state)
   1.355 +{
   1.356 +    if(state)
   1.357 +    {
   1.358 +        SDLVisualTest_EmptyActionQueue(&state->action_queue);
   1.359 +        SDLVisualTest_FreeSUTConfig(&state->sut_config);
   1.360 +    }
   1.361 +}
   1.362 \ No newline at end of file