mirror of
https://github.com/Relintai/sdl2_frt.git
synced 2024-12-20 22:16:49 +01:00
b72938c861
An existing hint lets apps that don't need the timer resolution changed avoid this, to save battery, etc, but this fixes several problems in timing, audio callbacks not firing fast enough, etc. Fixes Bugzilla #2944.
358 lines
10 KiB
C
358 lines
10 KiB
C
/* See COPYING.txt for the full license governing this code. */
|
|
/**
|
|
* \file harness_argparser.c
|
|
*
|
|
* Source file for functions to parse arguments to the test harness.
|
|
*/
|
|
|
|
#include <SDL_test.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "SDL_visualtest_harness_argparser.h"
|
|
#include "SDL_visualtest_rwhelper.h"
|
|
|
|
/** Maximum length of one line in the config file */
|
|
#define MAX_CONFIG_LINE_LEN 400
|
|
/** Default value for the timeout after which the SUT is forcefully killed */
|
|
#define DEFAULT_SUT_TIMEOUT (60 * 1000)
|
|
|
|
/* String compare s1 and s2 ignoring leading hyphens */
|
|
static int
|
|
StrCaseCmpIgnoreHyphen(char* s1, char* s2)
|
|
{
|
|
/* treat NULL pointer as empty strings */
|
|
if(!s1)
|
|
s1 = "";
|
|
if(!s2)
|
|
s2 = "";
|
|
|
|
while(*s1 == '-')
|
|
s1++;
|
|
while(*s2 == '-')
|
|
s2++;
|
|
|
|
return SDL_strcasecmp(s1, s2);
|
|
}
|
|
|
|
/* parser an argument, updates the state object and returns the number of
|
|
arguments processed; returns -1 on failure */
|
|
static int
|
|
ParseArg(char** argv, int index, SDLVisualTest_HarnessState* state)
|
|
{
|
|
if(!argv || !argv[index] || !state)
|
|
return 0;
|
|
|
|
if(StrCaseCmpIgnoreHyphen("sutapp", argv[index]) == 0)
|
|
{
|
|
index++;
|
|
if(!argv[index])
|
|
{
|
|
SDLTest_LogError("Arguments parsing error: Invalid argument for sutapp.");
|
|
return -1;
|
|
}
|
|
SDL_strlcpy(state->sutapp, argv[index], MAX_PATH_LEN);
|
|
SDLTest_Log("SUT Application: %s", state->sutapp);
|
|
return 2;
|
|
}
|
|
else if(StrCaseCmpIgnoreHyphen("output-dir", argv[index]) == 0)
|
|
{
|
|
index++;
|
|
if(!argv[index])
|
|
{
|
|
SDLTest_LogError("Arguments parsing error: Invalid argument for output-dir.");
|
|
return -1;
|
|
}
|
|
SDL_strlcpy(state->output_dir, argv[index], MAX_PATH_LEN);
|
|
SDLTest_Log("Screenshot Output Directory: %s", state->output_dir);
|
|
return 2;
|
|
}
|
|
else if(StrCaseCmpIgnoreHyphen("verify-dir", argv[index]) == 0)
|
|
{
|
|
index++;
|
|
if(!argv[index])
|
|
{
|
|
SDLTest_LogError("Arguments parsing error: Invalid argument for verify-dir.");
|
|
return -1;
|
|
}
|
|
SDL_strlcpy(state->verify_dir, argv[index], MAX_PATH_LEN);
|
|
SDLTest_Log("Screenshot Verification Directory: %s", state->verify_dir);
|
|
return 2;
|
|
}
|
|
else if(StrCaseCmpIgnoreHyphen("sutargs", argv[index]) == 0)
|
|
{
|
|
index++;
|
|
if(!argv[index])
|
|
{
|
|
SDLTest_LogError("Arguments parsing error: Invalid argument for sutargs.");
|
|
return -1;
|
|
}
|
|
SDL_strlcpy(state->sutargs, argv[index], MAX_SUT_ARGS_LEN);
|
|
SDLTest_Log("SUT Arguments: %s", state->sutargs);
|
|
return 2;
|
|
}
|
|
else if(StrCaseCmpIgnoreHyphen("timeout", argv[index]) == 0)
|
|
{
|
|
int hr, min, sec;
|
|
index++;
|
|
if(!argv[index] || SDL_sscanf(argv[index], "%d:%d:%d", &hr, &min, &sec) != 3)
|
|
{
|
|
SDLTest_LogError("Arguments parsing error: Invalid argument for timeout.");
|
|
return -1;
|
|
}
|
|
state->timeout = (((hr * 60) + min) * 60 + sec) * 1000;
|
|
SDLTest_Log("Maximum Timeout for each SUT run: %d milliseconds",
|
|
state->timeout);
|
|
return 2;
|
|
}
|
|
else if(StrCaseCmpIgnoreHyphen("parameter-config", argv[index]) == 0)
|
|
{
|
|
index++;
|
|
if(!argv[index])
|
|
{
|
|
SDLTest_LogError("Arguments parsing error: Invalid argument for parameter-config.");
|
|
return -1;
|
|
}
|
|
SDLTest_Log("SUT Parameters file: %s", argv[index]);
|
|
SDLVisualTest_FreeSUTConfig(&state->sut_config);
|
|
if(!SDLVisualTest_ParseSUTConfig(argv[index], &state->sut_config))
|
|
{
|
|
SDLTest_LogError("Failed to parse SUT parameters file");
|
|
return -1;
|
|
}
|
|
return 2;
|
|
}
|
|
else if(StrCaseCmpIgnoreHyphen("variator", argv[index]) == 0)
|
|
{
|
|
index++;
|
|
if(!argv[index])
|
|
{
|
|
SDLTest_LogError("Arguments parsing error: Invalid argument for variator.");
|
|
return -1;
|
|
}
|
|
SDLTest_Log("Variator: %s", argv[index]);
|
|
if(SDL_strcasecmp("exhaustive", argv[index]) == 0)
|
|
state->variator_type = SDL_VARIATOR_EXHAUSTIVE;
|
|
else if(SDL_strcasecmp("random", argv[index]) == 0)
|
|
state->variator_type = SDL_VARIATOR_RANDOM;
|
|
else
|
|
{
|
|
SDLTest_LogError("Arguments parsing error: Invalid variator name.");
|
|
return -1;
|
|
}
|
|
return 2;
|
|
}
|
|
else if(StrCaseCmpIgnoreHyphen("num-variations", argv[index]) == 0)
|
|
{
|
|
index++;
|
|
if(!argv[index])
|
|
{
|
|
SDLTest_LogError("Arguments parsing error: Invalid argument for num-variations.");
|
|
return -1;
|
|
}
|
|
state->num_variations = SDL_atoi(argv[index]);
|
|
SDLTest_Log("Number of variations to run: %d", state->num_variations);
|
|
if(state->num_variations <= 0)
|
|
{
|
|
SDLTest_LogError("Arguments parsing error: num-variations must be positive.");
|
|
return -1;
|
|
}
|
|
return 2;
|
|
}
|
|
else if(StrCaseCmpIgnoreHyphen("no-launch", argv[index]) == 0)
|
|
{
|
|
state->no_launch = SDL_TRUE;
|
|
SDLTest_Log("SUT will not be launched.");
|
|
return 1;
|
|
}
|
|
else if(StrCaseCmpIgnoreHyphen("action-config", argv[index]) == 0)
|
|
{
|
|
index++;
|
|
if(!argv[index])
|
|
{
|
|
SDLTest_LogError("Arguments parsing error: invalid argument for action-config");
|
|
return -1;
|
|
}
|
|
SDLTest_Log("Action Config file: %s", argv[index]);
|
|
SDLVisualTest_EmptyActionQueue(&state->action_queue);
|
|
if(!SDLVisualTest_ParseActionConfig(argv[index], &state->action_queue))
|
|
{
|
|
SDLTest_LogError("SDLVisualTest_ParseActionConfig() failed");
|
|
return -1;
|
|
}
|
|
return 2;
|
|
}
|
|
else if(StrCaseCmpIgnoreHyphen("config", argv[index]) == 0)
|
|
{
|
|
index++;
|
|
if(!argv[index])
|
|
{
|
|
SDLTest_LogError("Arguments parsing error: invalid argument for config");
|
|
return -1;
|
|
}
|
|
|
|
/* do nothing, this option has already been handled */
|
|
return 2;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* TODO: Trailing/leading spaces and spaces between equals sign not supported. */
|
|
static int
|
|
ParseConfig(char* file, SDLVisualTest_HarnessState* state)
|
|
{
|
|
SDL_RWops* rw;
|
|
SDLVisualTest_RWHelperBuffer buffer;
|
|
char line[MAX_CONFIG_LINE_LEN];
|
|
|
|
rw = SDL_RWFromFile(file, "r");
|
|
if(!rw)
|
|
{
|
|
SDLTest_LogError("SDL_RWFromFile() failed");
|
|
return 0;
|
|
}
|
|
|
|
SDLVisualTest_RWHelperResetBuffer(&buffer);
|
|
while(SDLVisualTest_RWHelperReadLine(rw, line, MAX_CONFIG_LINE_LEN,
|
|
&buffer, '#'))
|
|
{
|
|
char** argv;
|
|
int i, num_params;
|
|
|
|
/* count number of parameters and replace the trailing newline with 0 */
|
|
num_params = 1;
|
|
for(i = 0; line[i]; i++)
|
|
{
|
|
if(line[i] == '=')
|
|
{
|
|
num_params = 2;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* populate argv */
|
|
argv = (char**)SDL_malloc((num_params + 1) * sizeof(char*));
|
|
if(!argv)
|
|
{
|
|
SDLTest_LogError("malloc() failed.");
|
|
SDL_RWclose(rw);
|
|
return 0;
|
|
}
|
|
|
|
argv[num_params] = NULL;
|
|
for(i = 0; i < num_params; i++)
|
|
{
|
|
argv[i] = strtok(i == 0 ? line : NULL, "=");
|
|
}
|
|
|
|
if(ParseArg(argv, 0, state) == -1)
|
|
{
|
|
SDLTest_LogError("ParseArg() failed");
|
|
SDL_free(argv);
|
|
SDL_RWclose(rw);
|
|
return 0;
|
|
}
|
|
SDL_free(argv);
|
|
}
|
|
SDL_RWclose(rw);
|
|
|
|
if(!state->sutapp[0])
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
SDLVisualTest_ParseHarnessArgs(char** argv, SDLVisualTest_HarnessState* state)
|
|
{
|
|
int i;
|
|
|
|
SDLTest_Log("Parsing commandline arguments..");
|
|
|
|
if(!argv)
|
|
{
|
|
SDLTest_LogError("argv is NULL");
|
|
return 0;
|
|
}
|
|
if(!state)
|
|
{
|
|
SDLTest_LogError("state is NULL");
|
|
return 0;
|
|
}
|
|
|
|
/* initialize the state object */
|
|
state->sutargs[0] = '\0';
|
|
state->sutapp[0] = '\0';
|
|
state->output_dir[0] = '\0';
|
|
state->verify_dir[0] = '\0';
|
|
state->timeout = DEFAULT_SUT_TIMEOUT;
|
|
SDL_memset(&state->sut_config, 0, sizeof(SDLVisualTest_SUTConfig));
|
|
SDL_memset(&state->action_queue, 0, sizeof(SDLVisualTest_ActionQueue));
|
|
state->variator_type = SDL_VARIATOR_RANDOM;
|
|
state->num_variations = -1;
|
|
state->no_launch = SDL_FALSE;
|
|
|
|
/* parse config file if passed */
|
|
for(i = 0; argv[i]; i++)
|
|
{
|
|
if(StrCaseCmpIgnoreHyphen("config", argv[i]) == 0)
|
|
{
|
|
if(!argv[i + 1])
|
|
{
|
|
SDLTest_Log("Arguments parsing error: invalid argument for config.");
|
|
return 0;
|
|
}
|
|
if(!ParseConfig(argv[i + 1], state))
|
|
{
|
|
SDLTest_LogError("ParseConfig() failed");
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* parse the arguments */
|
|
for(i = 0; argv[i];)
|
|
{
|
|
int consumed = ParseArg(argv, i, state);
|
|
if(consumed == -1 || consumed == 0)
|
|
{
|
|
SDLTest_LogError("ParseArg() failed");
|
|
return 0;
|
|
}
|
|
i += consumed;
|
|
}
|
|
|
|
if(state->variator_type == SDL_VARIATOR_RANDOM && state->num_variations == -1)
|
|
state->num_variations = 1;
|
|
|
|
/* check to see if required options have been passed */
|
|
if(!state->sutapp[0])
|
|
{
|
|
SDLTest_LogError("sutapp must be passed.");
|
|
return 0;
|
|
}
|
|
if(!state->sutargs[0] && !state->sut_config.options)
|
|
{
|
|
SDLTest_LogError("Either sutargs or parameter-config must be passed.");
|
|
return 0;
|
|
}
|
|
if(!state->output_dir[0])
|
|
{
|
|
SDL_strlcpy(state->output_dir, "./output", MAX_PATH_LEN);
|
|
}
|
|
if(!state->verify_dir[0])
|
|
{
|
|
SDL_strlcpy(state->verify_dir, "./verify", MAX_PATH_LEN);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
SDLVisualTest_FreeHarnessState(SDLVisualTest_HarnessState* state)
|
|
{
|
|
if(state)
|
|
{
|
|
SDLVisualTest_EmptyActionQueue(&state->action_queue);
|
|
SDLVisualTest_FreeSUTConfig(&state->sut_config);
|
|
}
|
|
} |