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}