X-Git-Url: http://git.efficios.com/?p=argpar.git;a=blobdiff_plain;f=tests%2Ftest_argpar.c;h=c78b6e8a6babb71c7b362ba62eb45932e84644fb;hp=f4944eac1e37d1a836e80966ae4118d1e166c45e;hb=dd757a651292048da829dd6fa085c1f107569bcc;hpb=430fe8864aa297e333761b75eaad70900043e3d3 diff --git a/tests/test_argpar.c b/tests/test_argpar.c index f4944ea..c78b6e8 100644 --- a/tests/test_argpar.c +++ b/tests/test_argpar.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019 Philippe Proulx + * Copyright (c) 2019-2021 Philippe Proulx + * Copyright (c) 2020-2021 Simon Marchi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,33 +19,94 @@ #include #include #include +#include #include #include "tap/tap.h" #include "argpar/argpar.h" /* - * Tests that the command line `cmdline`, with non-quoted - * space-delimited arguments, once parsed given the option descriptors - * `descrs` and the option `fail_on_unknown_opt`, succeeds and gives the - * expected command line `expected_cmd_line` and number of ingested - * original arguments `expected_ingested_orig_args`. + * Formats `item` and appends the resulting string to `res_str` to + * incrementally build an expected command line string. * - * The resulting command-line is built from the resulting arguments, - * space-delimiting each argument, preferring the `--long-opt=arg` style - * over the `-s arg` style, and using the `arg` form for non-option - * arguments where `A` is the original argument index and `B` is the - * non-option argument index. + * This function: + * + * * Prefers the `--long-opt=arg` style over the `-s arg` style. + * + * * Uses the `arg` form for non-option arguments, where `A` is the + * original argument index and `B` is the non-option argument index. + */ +static +void append_to_res_str(GString * const res_str, + const struct argpar_item * const item) +{ + if (res_str->len > 0) { + g_string_append_c(res_str, ' '); + } + + switch (argpar_item_type(item)) { + case ARGPAR_ITEM_TYPE_OPT: + { + const struct argpar_opt_descr * const descr = + argpar_item_opt_descr(item); + const char * const arg = argpar_item_opt_arg(item); + + if (descr->long_name) { + g_string_append_printf(res_str, "--%s", + descr->long_name); + + if (arg) { + g_string_append_printf(res_str, "=%s", arg); + } + } else if (descr->short_name) { + g_string_append_printf(res_str, "-%c", + descr->short_name); + + if (arg) { + g_string_append_printf(res_str, " %s", arg); + } + } + + break; + } + case ARGPAR_ITEM_TYPE_NON_OPT: + { + const char * const arg = argpar_item_non_opt_arg(item); + const unsigned int orig_index = + argpar_item_non_opt_orig_index(item); + const unsigned int non_opt_index = + argpar_item_non_opt_non_opt_index(item); + + g_string_append_printf(res_str, "%s<%u,%u>", arg, orig_index, + non_opt_index); + break; + } + default: + abort(); + } +} + +/* + * Parses `cmdline` with argpar_parse() using the option descriptors + * `descrs`, and ensures that the resulting effective command line is + * `expected_cmd_line` and that the number of ingested original + * arguments is `expected_ingested_orig_args`. + * + * This function splits `cmdline` on spaces to create an original + * argument array. + * + * This function builds the resulting command line from parsing items + * by space-separating each formatted item (see append_to_res_str()). */ static -void test_succeed(const char *cmdline, - const char *expected_cmd_line, - const struct argpar_opt_descr *descrs, - unsigned int expected_ingested_orig_args) +void test_succeed_argpar_parse(const char * const cmdline, + const char * const expected_cmd_line, + const struct argpar_opt_descr * const descrs, + const unsigned int expected_ingested_orig_args) { struct argpar_parse_ret parse_ret; - GString *res_str = g_string_new(NULL); - gchar **argv = g_strsplit(cmdline, " ", 0); + GString * const res_str = g_string_new(NULL); + gchar ** const argv = g_strsplit(cmdline, " ", 0); unsigned int i; assert(argv); @@ -54,85 +116,156 @@ void test_succeed(const char *cmdline, ok(parse_ret.items, "argpar_parse() succeeds for command line `%s`", cmdline); ok(!parse_ret.error, - "argpar_parse() does not write an error for command line `%s`", cmdline); + "argpar_parse() doesn't set an error for command line `%s`", + cmdline); ok(parse_ret.ingested_orig_args == expected_ingested_orig_args, "argpar_parse() returns the correct number of ingested " "original arguments for command line `%s`", cmdline); + if (parse_ret.ingested_orig_args != expected_ingested_orig_args) { diag("Expected: %u Got: %u", expected_ingested_orig_args, parse_ret.ingested_orig_args); } if (!parse_ret.items) { - fail("argpar_parse() returns the expected parsed arguments " + fail("argpar_parse() returns the expected parsing items " "for command line `%s`", cmdline); goto end; } for (i = 0; i < parse_ret.items->n_items; i++) { - const struct argpar_item *arg = parse_ret.items->items[i]; - - switch (arg->type) { - case ARGPAR_ITEM_TYPE_OPT: - { - const struct argpar_item_opt *arg_opt = - (const void *) arg; - - if (arg_opt->descr->long_name) { - g_string_append_printf(res_str, "--%s", - arg_opt->descr->long_name); - - if (arg_opt->arg) { - g_string_append_printf(res_str, "=%s", - arg_opt->arg); - } - - g_string_append_c(res_str, ' '); - } else if (arg_opt->descr->short_name) { - g_string_append_printf(res_str, "-%c", - arg_opt->descr->short_name); - - if (arg_opt->arg) { - g_string_append_printf(res_str, " %s", - arg_opt->arg); - } - - g_string_append_c(res_str, ' '); - } + append_to_res_str(res_str, parse_ret.items->items[i]); + } - break; + ok(strcmp(expected_cmd_line, res_str->str) == 0, + "argpar_parse() returns the expected parsed arguments " + "for command line `%s`", cmdline); + + if (strcmp(expected_cmd_line, res_str->str) != 0) { + diag("Expected: `%s`", expected_cmd_line); + diag("Got: `%s`", res_str->str); + } + +end: + argpar_parse_ret_fini(&parse_ret); + g_string_free(res_str, TRUE); + g_strfreev(argv); +} + +/* + * Parses `cmdline` with the iterator API using the option descriptors + * `descrs`, and ensures that the resulting effective command line is + * `expected_cmd_line` and that the number of ingested original + * arguments is `expected_ingested_orig_args`. + * + * This function splits `cmdline` on spaces to create an original + * argument array. + * + * This function builds the resulting command line from parsing items + * by space-separating each formatted item (see append_to_res_str()). + */ +static +void test_succeed_argpar_iter(const char * const cmdline, + const char * const expected_cmd_line, + const struct argpar_opt_descr * const descrs, + const unsigned int expected_ingested_orig_args) +{ + struct argpar_iter *iter = NULL; + const struct argpar_item *item = NULL; + char *error = NULL; + GString * const res_str = g_string_new(NULL); + gchar ** const argv = g_strsplit(cmdline, " ", 0); + unsigned int i, actual_ingested_orig_args; + + assert(argv); + assert(res_str); + iter = argpar_iter_create(g_strv_length(argv), + (const char * const *) argv, descrs); + assert(iter); + + for (i = 0; ; i++) { + enum argpar_iter_next_status status; + + ARGPAR_ITEM_DESTROY_AND_RESET(item); + status = argpar_iter_next(iter, &item, &error); + + ok(status == ARGPAR_ITER_NEXT_STATUS_OK || + status == ARGPAR_ITER_NEXT_STATUS_END || + status == ARGPAR_ITER_NEXT_STATUS_ERROR_UNKNOWN_OPT, + "argpar_iter_next() returns the expected status " + "(%d) for command line `%s` (call %u)", + status, cmdline, i + 1); + + if (status == ARGPAR_ITER_NEXT_STATUS_ERROR_UNKNOWN_OPT) { + ok(error, + "argpar_iter_next() sets an error for " + "status `ARGPAR_ITER_NEXT_STATUS_ERROR_UNKNOWN_OPT` " + "and command line `%s` (call %u)", + cmdline, i + 1); + } else { + ok(!error, + "argpar_iter_next() doesn't set an error " + "for other status than " + "`ARGPAR_ITER_NEXT_STATUS_ERROR_UNKNOWN_OPT` " + "and command line `%s` (call %u)", + cmdline, i + 1); } - case ARGPAR_ITEM_TYPE_NON_OPT: - { - const struct argpar_item_non_opt *arg_non_opt = - (const void *) arg; - - g_string_append_printf(res_str, "%s<%u,%u> ", - arg_non_opt->arg, arg_non_opt->orig_index, - arg_non_opt->non_opt_index); + + if (status == ARGPAR_ITER_NEXT_STATUS_END || + status == ARGPAR_ITER_NEXT_STATUS_ERROR_UNKNOWN_OPT) { + ok(!item, + "argpar_iter_next() doesn't set an item " + "for status `ARGPAR_ITER_NEXT_STATUS_END` " + "or `ARGPAR_ITER_NEXT_STATUS_ERROR_UNKNOWN_OPT` " + "and command line `%s` (call %u)", + cmdline, i + 1); break; } - default: - abort(); - } + + append_to_res_str(res_str, item); } - if (res_str->len > 0) { - g_string_truncate(res_str, res_str->len - 1); + actual_ingested_orig_args = argpar_iter_ingested_orig_args(iter); + ok(actual_ingested_orig_args == expected_ingested_orig_args, + "argpar_iter_ingested_orig_args() returns the expected " + "number of ingested original arguments for command line `%s`", + cmdline); + + if (actual_ingested_orig_args != expected_ingested_orig_args) { + diag("Expected: %u Got: %u", expected_ingested_orig_args, + actual_ingested_orig_args); } ok(strcmp(expected_cmd_line, res_str->str) == 0, - "argpar_parse() returns the expected parsed arguments " + "argpar_iter_next() returns the expected parsing items " "for command line `%s`", cmdline); + if (strcmp(expected_cmd_line, res_str->str) != 0) { diag("Expected: `%s`", expected_cmd_line); diag("Got: `%s`", res_str->str); } -end: - argpar_parse_ret_fini(&parse_ret); + argpar_item_destroy(item); + argpar_iter_destroy(iter); g_string_free(res_str, TRUE); g_strfreev(argv); + free(error); +} + +/* + * Calls test_succeed_argpar_parse() and test_succeed_argpar_iter() + * with the provided parameters. + */ +static +void test_succeed(const char * const cmdline, + const char * const expected_cmd_line, + const struct argpar_opt_descr * const descrs, + const unsigned int expected_ingested_orig_args) +{ + test_succeed_argpar_parse(cmdline, expected_cmd_line, descrs, + expected_ingested_orig_args); + test_succeed_argpar_iter(cmdline, expected_cmd_line, descrs, + expected_ingested_orig_args); } static @@ -491,35 +624,67 @@ void succeed_tests(void) "-f --yeah= -f", descrs, 3); } + + /* `-` non-option argument */ + { + const struct argpar_opt_descr descrs[] = { + { 0, 'f', NULL, false }, + ARGPAR_OPT_DESCR_SENTINEL + }; + + test_succeed( + "-f - -f", + "-f -<1,0> -f", + descrs, 3); + } + + /* `--` non-option argument */ + { + const struct argpar_opt_descr descrs[] = { + { 0, 'f', NULL, false }, + ARGPAR_OPT_DESCR_SENTINEL + }; + + test_succeed( + "-f -- -f", + "-f --<1,0> -f", + descrs, 3); + } } /* - * Tests that the command line `cmdline`, with non-quoted - * space-delimited arguments, once parsed given the option descriptors - * `descrs`, fails and gives the expected error `expected_error`. + * Parses `cmdline` with argpar_parse() using the option descriptors + * `descrs`, and ensures that the function fails and that it sets an + * error which is equal to `expected_error`. + * + * This function splits `cmdline` on spaces to create an original + * argument array. */ static -void test_fail(const char *cmdline, const char *expected_error, - const struct argpar_opt_descr *descrs) +void test_fail_argpar_parse(const char * const cmdline, + const char * const expected_error, + const struct argpar_opt_descr * const descrs) { struct argpar_parse_ret parse_ret; - gchar **argv = g_strsplit(cmdline, " ", 0); + gchar ** const argv = g_strsplit(cmdline, " ", 0); parse_ret = argpar_parse(g_strv_length(argv), (const char * const *) argv, descrs, true); ok(!parse_ret.items, "argpar_parse() fails for command line `%s`", cmdline); ok(parse_ret.error, - "argpar_parse() writes an error string for command line `%s`", + "argpar_parse() sets an error string for command line `%s`", cmdline); + if (parse_ret.items) { - fail("argpar_parse() writes the expected error string"); + fail("argpar_parse() sets the expected error string"); goto end; } ok(strcmp(expected_error, parse_ret.error) == 0, - "argpar_parse() writes the expected error string " + "argpar_parse() sets the expected error string " "for command line `%s`", cmdline); + if (strcmp(expected_error, parse_ret.error) != 0) { diag("Expected: `%s`", expected_error); diag("Got: `%s`", parse_ret.error); @@ -530,6 +695,99 @@ end: g_strfreev(argv); } +/* + * Parses `cmdline` with the iterator API using the option descriptors + * `descrs`, and ensures that argpar_iter_next() fails with status + * `expected_status` and that it sets an error which is equal to + * `expected_error`. + * + * This function splits `cmdline` on spaces to create an original + * argument array. + */ +static +void test_fail_argpar_iter(const char * const cmdline, + const char * const expected_error, + const enum argpar_iter_next_status expected_status, + const struct argpar_opt_descr * const descrs) +{ + struct argpar_iter *iter = NULL; + const struct argpar_item *item = NULL; + gchar ** const argv = g_strsplit(cmdline, " ", 0); + unsigned int i; + char *error = NULL; + + iter = argpar_iter_create(g_strv_length(argv), + (const char * const *) argv, descrs); + assert(iter); + + for (i = 0; ; i++) { + enum argpar_iter_next_status status; + + ARGPAR_ITEM_DESTROY_AND_RESET(item); + status = argpar_iter_next(iter, &item, &error); + ok(status == ARGPAR_ITER_NEXT_STATUS_OK || + status == expected_status, + "argpar_iter_next() returns the expected status " + "(%d) for command line `%s` (call %u)", + status, cmdline, i + 1); + + if (status != ARGPAR_ITER_NEXT_STATUS_OK) { + ok(!item, + "argpar_iter_next() doesn't set an item " + "for other status than " + "`ARGPAR_ITER_NEXT_STATUS_OK` " + "and command line `%s` (call %u)", + cmdline, i + 1); + ok(error, + "argpar_iter_next() sets an error for " + "other status than " + " `ARGPAR_ITER_NEXT_STATUS_OK` " + "and command line `%s` (call %u)", + cmdline, i + 1); + break; + } + + ok(item, + "argpar_iter_next() sets an item for status " + "`ARGPAR_ITER_NEXT_STATUS_OK` " + "and command line `%s` (call %u)", + cmdline, i + 1); + ok(!error, + "argpar_iter_next() doesn't set an error for status " + "`ARGPAR_ITER_NEXT_STATUS_OK` " + "and command line `%s` (call %u)", + cmdline, i + 1); + } + + ok(strcmp(expected_error, error) == 0, + "argpar_iter_next() sets the expected error string " + "for command line `%s`", cmdline); + + if (strcmp(expected_error, error) != 0) { + diag("Expected: `%s`", expected_error); + diag("Got: `%s`", error); + } + + argpar_item_destroy(item); + argpar_iter_destroy(iter); + free(error); + g_strfreev(argv); +} + +/* + * Calls test_fail_argpar_parse() and test_fail_argpar_iter() with the + * provided parameters. + */ +static +void test_fail(const char * const cmdline, const char * const expected_error, + const enum argpar_iter_next_status expected_iter_next_status, + const struct argpar_opt_descr * const descrs) +{ + test_fail_argpar_parse(cmdline, expected_error, descrs); + test_fail_argpar_iter(cmdline, expected_error, + expected_iter_next_status, descrs); +} + static void fail_tests(void) { @@ -543,6 +801,7 @@ void fail_tests(void) test_fail( "--thumb=party --meow", "While parsing argument #2 (`--meow`): Unknown option `--meow`", + ARGPAR_ITER_NEXT_STATUS_ERROR_UNKNOWN_OPT, descrs); } @@ -556,6 +815,7 @@ void fail_tests(void) test_fail( "--thumb=party -x", "While parsing argument #2 (`-x`): Unknown option `-x`", + ARGPAR_ITER_NEXT_STATUS_ERROR_UNKNOWN_OPT, descrs); } @@ -569,6 +829,7 @@ void fail_tests(void) test_fail( "--thumb", "While parsing argument #1 (`--thumb`): Missing required argument for option `--thumb`", + ARGPAR_ITER_NEXT_STATUS_ERROR_MISSING_OPT_ARG, descrs); } @@ -582,6 +843,7 @@ void fail_tests(void) test_fail( "-k", "While parsing argument #1 (`-k`): Missing required argument for option `-k`", + ARGPAR_ITER_NEXT_STATUS_ERROR_MISSING_OPT_ARG, descrs); } @@ -597,39 +859,11 @@ void fail_tests(void) test_fail( "-abc", "While parsing argument #1 (`-abc`): Missing required argument for option `-c`", + ARGPAR_ITER_NEXT_STATUS_ERROR_MISSING_OPT_ARG, descrs); } - /* Invalid `-` */ - { - const struct argpar_opt_descr descrs[] = { - { 0, 'a', NULL, false }, - { 0, 'b', NULL, false }, - { 0, 'c', NULL, true }, - ARGPAR_OPT_DESCR_SENTINEL - }; - - test_fail( - "-ab - -c", - "While parsing argument #2 (`-`): Invalid argument", - descrs); - } - - /* Invalid `--` */ - { - const struct argpar_opt_descr descrs[] = { - { 0, 'a', NULL, false }, - { 0, 'b', NULL, false }, - { 0, 'c', NULL, true }, - ARGPAR_OPT_DESCR_SENTINEL - }; - - test_fail( - "-ab -- -c", - "While parsing argument #2 (`--`): Invalid argument", - descrs); - } - + /* Unexpected long option argument */ { const struct argpar_opt_descr descrs[] = { { 0, 'c', "chevre", false }, @@ -639,13 +873,14 @@ void fail_tests(void) test_fail( "--chevre=fromage", "While parsing argument #1 (`--chevre=fromage`): Unexpected argument for option `--chevre`", + ARGPAR_ITER_NEXT_STATUS_ERROR_UNEXPECTED_OPT_ARG, descrs); } } int main(void) { - plan_tests(132); + plan_tests(423); succeed_tests(); fail_tests(); return exit_status();