visualtest/src/harness_argparser.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 23 May 2018 17:15:35 -0700
changeset 11999 f3fc4b3d54f6
parent 7924 fcb86d323770
permissions -rw-r--r--
Better fix for axis sorting with some Android controllers
     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 */
    21 static int
    22 StrCaseCmpIgnoreHyphen(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 */
    40 static int
    41 ParseArg(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. */
   201 static int
   202 ParseConfig(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 
   264 int
   265 SDLVisualTest_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 
   350 void
   351 SDLVisualTest_FreeHarnessState(SDLVisualTest_HarnessState* state)
   352 {
   353     if(state)
   354     {
   355         SDLVisualTest_EmptyActionQueue(&state->action_queue);
   356         SDLVisualTest_FreeSUTConfig(&state->sut_config);
   357     }
   358 }