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