diff --git a/src/arguments.c b/src/arguments.c index b6c9171..24c81ec 100644 --- a/src/arguments.c +++ b/src/arguments.c @@ -34,7 +34,7 @@ enum TdoError tdo_arguments_parse(struct TdoArguments *args, int argc, char **ar } } else { // flag - if (strncmp(s, "-t", 3) == 0) { + if (strcmp(s, "-t") == 0) { if (argc <= 1) { fprintf(stderr, "Missing test argument to '-t'\n"); result = TDO_ERROR_ARG_PARSE; @@ -43,9 +43,24 @@ enum TdoError tdo_arguments_parse(struct TdoArguments *args, int argc, char **ar args->single_test = argv[0]; } } else if (strncmp(s, "-j", 2) == 0) { + char const *job_str = NULL; + if (strcmp(s, "-j") == 0) { + if (argc <= 1) { + fprintf(stderr, "Missing job argument to '-j'\n"); + result = TDO_ERROR_ARG_PARSE; + argc -= 1; argv += 1; + continue; + } else { + argc -= 1; argv += 1; + job_str = argv[0]; + } + } else { + job_str = s + 2; + } + errno = 0; char *err; - unsigned long threads = strtoul(s + 2, &err, 10); + unsigned long threads = strtoul(job_str, &err, 10); if (errno) { perror("Could not parse amount of processes"); result = TDO_ERROR_ARG_PARSE; @@ -61,7 +76,7 @@ enum TdoError tdo_arguments_parse(struct TdoArguments *args, int argc, char **ar } else { args->processes = (size_t) threads; } - } else if (strncmp(s, "-o", 3) == 0) { + } else if (strcmp(s, "-o") == 0) { if (argc <= 1) { fprintf(stderr, "Missing output file argument to '-o'\n"); result = TDO_ERROR_ARG_PARSE; @@ -69,9 +84,9 @@ enum TdoError tdo_arguments_parse(struct TdoArguments *args, int argc, char **ar argc -= 1; argv += 1; args->output = argv[0]; } - } else if (strncmp(s, "-f", 3) == 0) { + } else if (strcmp(s, "-f") == 0) { args->overwrite = true; - } else if (strncmp(s, "--internal-status", 18) == 0) { + } else if (strcmp(s, "--internal-status") == 0) { if (argc <= 1) { fprintf(stderr, "Missing status file\n"); result = TDO_ERROR_ARG_PARSE; @@ -79,9 +94,9 @@ enum TdoError tdo_arguments_parse(struct TdoArguments *args, int argc, char **ar argc -= 1; argv += 1; args->internal_status = argv[0]; } - } else if (strncmp(s, "--timeout", 10) == 0) { + } else if (strcmp(s, "--timeout") == 0) { if (argc <= 1) { - fprintf(stderr, "Missing timeout argument\n"); + fprintf(stderr, "Missing timeout argument to '--timeout'\n"); result = TDO_ERROR_ARG_PARSE; } else { argc -= 1; argv += 1; @@ -91,13 +106,13 @@ enum TdoError tdo_arguments_parse(struct TdoArguments *args, int argc, char **ar char *err; float timeout = strtof(timeout_str, &err); if (errno) { - perror("Could not parse amount of processes"); + perror("Could not parse timeout"); result = TDO_ERROR_ARG_PARSE; } else if (*err != '\0') { - fprintf(stderr, "Could not parse amount of threads: '%s'\n", timeout_str); + fprintf(stderr, "Could not parse timeout: '%s'\n", timeout_str); result = TDO_ERROR_ARG_PARSE; } else if (timeout <= 0) { - fprintf(stderr, "Amount of processes must be strictly positive, got %f\n", timeout); + fprintf(stderr, "Timeout must be strictly positive, got %f\n", timeout); result = TDO_ERROR_ARG_PARSE; } else { args->time_limit = timeout; diff --git a/src/main.c b/src/main.c index 1f25ae0..d7ee594 100644 --- a/src/main.c +++ b/src/main.c @@ -18,10 +18,52 @@ #include #include +#include + +static const char *tdo_help_text = + "Usage: tdo [OPTIONS] [TEST_FILE]\n" + " tdo [OPTIONS] -t \"TEST_DEFINITION\"\n" + " cat tests.txt | tdo [OPTIONS]\n" + "\n" + "A C99 test runner that executes tests defined by shared library symbols.\n" + "Every test is executed in a separate process which ensures that they do not\n" + "interact.\n" + "\n" + "Arguments:\n" + " TEST_FILE Path to a file containing test definitions. If omitted \n" + " and no -t flag is provided, definitions are read \n" + " from standard input (stdin).\n" + "\n" + "Options:\n" + " -t \"TEST_DEFINITION\" Run a single test definition string directly.\n" + " -j [N] Run tests in parallel using N processes (default: 1).\n" + " -o FILE Write results to the specified FILE.\n" + " -f Force overwrite the output file if it already exists.\n" + " --timeout SECONDS Set a maximum execution time per test (default: 5.0).\n" + " -h, --help Display this help message and exit.\n" + "\n" + "Test Definition Format:\n" + " Definitions follow a \"test-first\" structure:\n" + " test::PATH::SYMBOL [before::PATH::SYMBOL] [after::PATH::SYMBOL] ...\n" + "\n" + " - PATH: The path to the shared library (e.g., .so, .dll, or .dylib).\n" + " - SYMBOL: The name of the exported function to execute.\n" + "\n" + " Definitions can include any number of 'before' and 'after' hooks.\n" + " Example:\n" + " test::./lib.so::test_math before::./lib.so::setup after::./lib.so::clean\n" +; int main(int argc, char **argv) { enum TdoError result = TDO_ERROR_UNKNOWN; + for (int i = 0; i < argc; i++) { + if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { + fprintf(stderr, "%s", tdo_help_text); + return TDO_ERROR_OK; + } + } + struct TdoArguments args; result = tdo_arguments_parse(&args, argc, argv); if (result != TDO_ERROR_OK) goto error_parse_args;