visualtest/src/harness_argparser.c
changeset 7924 fcb86d323770
equal deleted inserted replaced
7923:d9ecdf71effb 7924:fcb86d323770
       
     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 }