diff --git a/test/build.sh b/test/build.sh new file mode 100755 index 0000000..fef814a --- /dev/null +++ b/test/build.sh @@ -0,0 +1,7 @@ +#!/usr/bin/bash +ctags ../args.h *.c *.cpp + +clang main.cpp -g -Wall + +clang main.c -std=c99 -g -Wall +./a.out diff --git a/test/main.c b/test/main.c new file mode 100644 index 0000000..fab9dfa --- /dev/null +++ b/test/main.c @@ -0,0 +1,344 @@ +int allocation_ratio; +char *ERRORS[256]; +int ERR_IDX; +#define ARGS_MALLOC(x) (allocation_ratio++, malloc(x)) +#define ARGS_FREE(x) (allocation_ratio--, free(x)) +#define ARGS_PRINTF(...) (ERRORS[ERR_IDX++] = strf(__VA_ARGS__)) + +#include +#include +#include +#include +char *strf(const char *fmt, ...) { + va_list args; + va_start(args, fmt); + size_t n = 1 + vsnprintf(NULL, 0, fmt, args); + va_end(args); + char *str = malloc(n); + va_start(args, fmt); + vsnprintf(str, n, fmt, args); + va_end(args); + return str; +} + +#define ARGS_IMPLEMENTATION +#include "../args.h" +#include + +void example(int argc, char **argv) { + args_t args = { + .program = argv[0], + .description = "this program does very cool things on many files and outputs it somewhere", + .epilogue = "it also shows cool epilogue text in it's help", + }; + args_add(&args, (args_desc_t){"filenames", .nargs = "+"}); + args_add(&args, (args_desc_t){"--output", "-o"}); + args_add(&args, (args_desc_t){"--force", "-f", .store_value = "1", .default_value = "0"}); + args_add(&args, (args_desc_t){"--recursive", "-r", .store_value = "1", .default_value = "0"}); + args_add(&args, (args_desc_t){"--help", "-h", .store_value = "1", .default_value = "0"}); + args_parse(&args, argc, argv); + + const char **filenames = args_get(&args, "filenames"); + const char **output = args_get(&args, "--output"); + int force = atoi(args_get(&args, "-f")[0]); + int recursive = atoi(args_get(&args, "--recursive")[0]); + int help = atoi(args_get(&args, "--help")[0]); + + for (int i = 0; filenames[i]; i += 1) { + // + } + + if (help) { + args_print_help(&args); + return; + } + // .. + + (void)filenames; (void)output; (void)force; (void)recursive; + args_free(&args); +} + +void example_single_positional_argument(int argc, char **argv) { + { + args_t args = {0}; + args_add(&args, (args_desc_t){"argument", .nargs = "1"}); + args_parse(&args, argc, argv); + const char *argument = args_get(&args, "argument")[0]; + (void)argument; + args_free(&args); + } + + { + args_t args = {0}; + args_add(&args, (args_desc_t){"arguments", .nargs = "+"}); + args_parse(&args, argc, argv); + const char **arguments = args_get(&args, "arguments"); + (void)arguments; + args_free(&args); + } + + { + args_t args = {0}; + args_add(&args, (args_desc_t){"--help", "-h", .store_value = "1", .default_value = "0"}); + args_parse(&args, argc, argv); + int help = atoi(args_get(&args, "help")[0]); + (void)help; + args_free(&args); + } + + { + args_t args = {0}; + args_add(&args, (args_desc_t){"--list", "-l", .type = ARGS_TYPE_INT, .nargs = "*"}); + args_parse(&args, argc, argv); + const char **list = args_get(&args, "--list"); + (void)list; + args_free(&args); + } +} + +void args_test_type(void) { + { + args_t args = {0}; + char *argv[] = {"./a.out", "--integer", "1", "--integer-list", "2", "3"}; + args_add(&args, (args_desc_t){"--integer", .nargs = "1", .type = ARGS_TYPE_INT}); + args_add(&args, (args_desc_t){"--integer-list", .nargs = "+", .type = ARGS_TYPE_INT}); + int errors = args_parse(&args, args_slen(argv), argv); + assert(errors == 0); + assert(atoi(args_get(&args, "--integer")[0]) == 1); + assert(atoi(args_get(&args, "--integer-list")[0]) == 2); + assert(atoi(args_get(&args, "--integer-list")[1]) == 3); + args_free(&args); + } + { + args_t args = {0}; + char *argv[] = {"./a.out", "--integer", "thing", "--integer-list", "2", "3"}; + args_add(&args, (args_desc_t){"--integer", .nargs = "1", .type = ARGS_TYPE_INT}); + args_add(&args, (args_desc_t){"--integer-list", .nargs = "+", .type = ARGS_TYPE_INT}); + int errors = args_parse(&args, args_slen(argv), argv); + assert(errors == 1); + assert(strstr(ERRORS[ERR_IDX - 1], "non integer value: 'thing'")); + assert(atoi(args_get(&args, "--integer-list")[0]) == 2); + assert(atoi(args_get(&args, "--integer-list")[1]) == 3); + args_free(&args); + } +} + +void args_test_regular(void) { + { + args_t args = {0}; + char *argv[] = {"./a.out", "--filename", "thing"}; + args_add(&args, (args_desc_t){"--filename", "-f"}); + int errors = args_parse(&args, args_slen(argv), argv); + assert(errors = 1); + const char **values = args_get(&args, "-f"); + assert(args_streq(values[0], "thing")); + args_free(&args); + } + + { + args_t args = {0}; + char *argv[] = {"./a.out", "--filename", "thing", "memes"}; + args_add(&args, (args_desc_t){"--filename", "-f", .nargs = "?"}); + int errors = args_parse(&args, args_slen(argv), argv); + assert(errors == 1); + assert(strstr(ERRORS[ERR_IDX - 1], "unrecognized argument: 'memes'")); + args_free(&args); + } + + { + args_t args = {0}; + char *argv[] = {"./a.out", "--filename"}; + args_add(&args, (args_desc_t){"--filename", "-f"}); + int errors = args_parse(&args, args_slen(argv), argv); + assert(errors == 1); + assert(strstr(ERRORS[ERR_IDX - 1], "expected a value to follow after argument: '--filename'")); + args_free(&args); + } + + { + char *argv[] = {"./a.out"}; + args_t args = {0}; + args_add(&args, (args_desc_t){"--filename", "-f", .default_value = "some_default"}); + int errors = args_parse(&args, args_slen(argv), argv); + assert(errors == 0); + const char **values = args_get(&args, "-f"); + assert(args_alen(values) == 2); + assert(args_streq(values[0], "some_default")); + args_free(&args); + } + + { + args_t args = {0}; + char *argv[] = {"./a.out"}; + args_add(&args, (args_desc_t){"--filename", "-f", .nargs = "0"}); + int errors = args_parse(&args, args_slen(argv), argv); + assert(errors == 0); + args_free(&args); + } + + { + args_t args = {0}; + char *argv[] = {"./a.out", "--filename", "a", "b", "c", "-f", "d"}; + args_add(&args, (args_desc_t){"--filename", "-f", .nargs = "*"}); + int errors = args_parse(&args, args_slen(argv), argv); + assert(errors == 0); + const char **values = args_get(&args, "-f"); + assert(args_alen(values) == 5); + assert(args_streq(values[0], "a")); + assert(args_streq(values[3], "d")); + args_free(&args); + } + + { + args_t args = {0}; + char *argv[] = {"./a.out", "--filename", "a", "b", "c", "-a", "app", "-f", "d", "--directory", "e", "f", "-d", "g", "-f", "h"}; + args_add(&args, (args_desc_t){"--filename", "-f", .nargs = "*"}); + args_add(&args, (args_desc_t){"--directory", "-d", .nargs = "+"}); + args_add(&args, (args_desc_t){"--application", "-a", .nargs = "?"}); + int errors = args_parse(&args, args_slen(argv), argv); + assert(errors == 0); + const char **values = args_get(&args, "-f"); + assert(args_alen(values) == 6); + assert(args_streq(values[0], "a")); + assert(args_streq(values[3], "d")); + + const char **values_app = args_get(&args, "-a"); + assert(args_alen(values_app) == 2); + assert(args_streq(values_app[0], "app")); + + const char **values_dir = args_get(&args, "--directory"); + assert(args_alen(values_dir) == 4); + + const char **values_other = args_get(&args, "--unknown"); + assert(values_other == NULL); + args_free(&args); + } +} + +void args_test_positional(void) { + { + args_t args = {0}; + char *argv[] = {"./a.out", "a", "--filename", "file", "c"}; + args_add(&args, (args_desc_t){"--filename", "-f", .nargs = "?"}); + args_add(&args, (args_desc_t){"pos", .nargs = "*"}); + int errors = args_parse(&args, args_slen(argv), argv); + assert(errors == 0); + const char **pos_value = args_get(&args, "pos"); + assert(args_alen(pos_value) == 3); + assert(args_streq(pos_value[0], "a")); + assert(args_streq(pos_value[1], "c")); + const char **f_values = args_get(&args, "-f"); + assert(args_alen(f_values) == 2); + assert(args_streq(f_values[0], "file")); + args_free(&args); + } + + { + args_t args = {0}; + char *argv[] = {"./a.out", "a", "--filename", "file", "file2", "b"}; + args_add(&args, (args_desc_t){"--filename", "-f", .nargs = "2"}); + args_add(&args, (args_desc_t){"pos", .nargs = "*"}); + int errors = args_parse(&args, args_slen(argv), argv); + assert(errors == 0); + const char **pos_value = args_get(&args, "pos"); + assert(args_alen(pos_value) == 3); + assert(args_streq(pos_value[0], "a")); + assert(args_streq(pos_value[1], "b")); + const char **f_values = args_get(&args, "-f"); + assert(args_alen(f_values) == 3); + assert(args_streq(f_values[0], "file")); + assert(args_streq(f_values[1], "file2")); + args_free(&args); + } + + { + args_t args = {0}; + char *argv[] = {"./a.out", "a", "--filename", "file", "file2", "b"}; + args_add(&args, (args_desc_t){"--filename", "-f", .nargs = "2"}); + args_add(&args, (args_desc_t){"pos", .nargs = "1"}); + int errors = args_parse(&args, args_slen(argv), argv); + assert(errors == 1); + assert(strstr(ERRORS[ERR_IDX - 1], "expected 1 arguments: 'pos', got 2 arguments")); + args_free(&args); + } +} + +void args_test_boolean(void) { + { + args_t args = {0}; + args_add(&args, (args_desc_t){"--boolean-flag", "-b", .nargs = "+", .default_value = "true", .store_value = "false"}); + char *argv[] = {"./a.out", "--boolean-flag"}; + int errors = args_parse(&args, args_slen(argv), argv); + + assert(errors == 0); + const char **value = args_get(&args, "-b"); + assert(args_alen(value) == 2); + assert(args_streq(value[0], "false")); + assert(value[1] == NULL); + args_free(&args); + } + + { + args_t args = {0}; + args_add(&args, (args_desc_t){"--boolean-flag", "-b", .nargs = "+", .default_value = "true", .store_value = "false"}); + char *argv[] = {"./a.out", "-b"}; + int errors = args_parse(&args, args_slen(argv), argv); + assert(errors == 0); + const char **value = args_get(&args, "--boolean-flag"); + assert(args_alen(value) == 2); + assert(args_streq(value[0], "false")); + assert(value[1] == NULL); + args_free(&args); + } + + { + args_t args = {0}; + args_add(&args, (args_desc_t){"--boolean-flag", "-b", .nargs = "+", .default_value = "true", .store_value = "false"}); + char *argv[] = {"./a.out", "-b", "--boolean-flag"}; + int errors = args_parse(&args, args_slen(argv), argv); + assert(errors == 0); + const char **value = args_get(&args, "--boolean-flag"); + assert(args_alen(value) == 3); + assert(args_streq(value[0], "false")); + assert(args_streq(value[1], "false")); + args_free(&args); + } + + { + args_t args = {0}; + char *argv[] = {"./a.out"}; + args_add(&args, (args_desc_t){"--boolean-flag", "-b", .nargs = "*", .default_value = "true", .store_value = "false"}); + int errors = args_parse(&args, args_slen(argv), argv); + assert(errors == 0); + const char **value = args_get(&args, "-b"); + assert(args_alen(value) == 2); + assert(args_streq(value[0], "true")); + assert(value[1] == NULL); + args_free(&args); + } + + { + args_t args = {0}; + char *argv[] = {"./a.out"}; + args_add(&args, (args_desc_t){"--boolean-flag", "-b", .nargs = "1", .default_value = "true", .store_value = "false"}); + int errors = args_parse(&args, args_slen(argv), argv); + assert(errors == 1); + assert(strstr(ERRORS[ERR_IDX - 1], "expected 1 arguments")); + assert(strstr(ERRORS[ERR_IDX - 1], "--boolean-flag")); + args_free(&args); + } +} + +void args_test_scratch(void) { +} + +int main() { + args_test_scratch(); + args_test_boolean(); + args_test_positional(); + args_test_regular(); + args_test_type(); + example(8, (char*[]){"a.out", "file1", "file2", "file3", "-o", "/dir", "--force", "file4"}); + assert(allocation_ratio == 0); + return 0; +} diff --git a/test/main.cpp b/test/main.cpp new file mode 100644 index 0000000..f5d9c4a --- /dev/null +++ b/test/main.cpp @@ -0,0 +1,51 @@ +#define ARGS_IMPLEMENTATION +#include "../args.h" +#include + +void args_add_bool(args_t *args, const char *name, const char *alt_name, const char *help) { + args_desc_t desc = {name, alt_name}; + desc.help = help; + desc.store_value = "1"; + desc.default_value = "0"; + args_add(args, desc); +} + +void args_add_nargs(args_t *args, const char *name, const char *alt_name, const char *nargs, const char *help) { + args_desc_t desc = {name, alt_name}; + desc.nargs = nargs; + desc.help = help; + args_add(args, desc); +} + +int main(int argc, char **argv) { + args_t args = { + .program = argv[0], + .description = (char *)"this program does very cool things on many files and outputs it somewhere", + .epilogue = (char *)"it also shows cool epilogue text in it's help", + }; + args_add_nargs(&args, "filenames", NULL, "+", "list of filenames to process"); + args_add_nargs(&args, "--output", "-o", "?", "path to the folder where output will be gathered"); + args_add_bool(&args, "--force", "-f", "force the processing"); + args_add_bool(&args, "--recursive", "-r", "apply recursively to files in current directory"); + args_add_bool(&args, "--help", "-h", "show this help window"); + args_parse(&args, argc, argv); + + const char **filenames = args_get(&args, "filenames"); + const char **output = args_get(&args, "--output"); + int force = atoi(args_get(&args, "-f")[0]); + int recursive = atoi(args_get(&args, "--recursive")[0]); + int help = atoi(args_get(&args, "--help")[0]); + + for (int i = 0; filenames[i]; i += 1) { + // + } + + if (help) { + args_print_help(&args); + return 0; + } + // .. + + (void)filenames; (void)output; (void)force; (void)recursive; + args_free(&args); +}