diff options
| author | Lion Kortlepel <[email protected]> | 2026-01-22 23:18:16 +0100 |
|---|---|---|
| committer | Lion Kortlepel <[email protected]> | 2026-01-22 23:18:16 +0100 |
| commit | 2d2be7e2b38031f7cd826f78543b18a287423ad7 (patch) | |
| tree | 2bf0eba1995000e8d95cffae4101486541ce6eeb /tests | |
| parent | 36fdeca43eab4439a117d4c912f87e704eaa9cd5 (diff) | |
| download | args-2d2be7e2b38031f7cd826f78543b18a287423ad7.tar.zst args-2d2be7e2b38031f7cd826f78543b18a287423ad7.zip | |
fix!: reach 96% line coverage, add tests, fix bugs
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/ls_test.h | 16 | ||||
| -rw-r--r-- | tests/tests.c | 286 |
2 files changed, 283 insertions, 19 deletions
diff --git a/tests/ls_test.h b/tests/ls_test.h index 5dda4aa..31d87f8 100644 --- a/tests/ls_test.h +++ b/tests/ls_test.h @@ -1,6 +1,6 @@ /* Lion's Standard (LS) test harness. * - * Version: 1.1 + * Version: 1.2 * Website: https://libls.org * Repo: https://github.com/libls/test * SPDX-License-Identifier: MIT @@ -96,6 +96,8 @@ _func += 6; \ fprintf(stderr, "%s: FAILED: %s (%s:%d)\n", _func, #cond, \ __FILE__, __LINE__); \ + ++lst_fail; \ + return 1; \ } \ } while (0) @@ -115,7 +117,6 @@ ++lst_fail; \ return 1; \ } \ - ++lst_ok; \ } while (0) #define ASSERT_NEQ(a, b, fmt) \ @@ -132,7 +133,6 @@ ++lst_fail; \ return 1; \ } \ - ++lst_ok; \ } while (0) #define ASSERT_LT(a, b, fmt) \ @@ -149,7 +149,6 @@ ++lst_fail; \ return 1; \ } \ - ++lst_ok; \ } while (0) #define ASSERT_LE(a, b, fmt) \ @@ -166,7 +165,6 @@ ++lst_fail; \ return 1; \ } \ - ++lst_ok; \ } while (0) #define ASSERT_GT(a, b, fmt) \ @@ -183,7 +181,6 @@ ++lst_fail; \ return 1; \ } \ - ++lst_ok; \ } while (0) #define ASSERT_GE(a, b, fmt) \ @@ -200,7 +197,6 @@ ++lst_fail; \ return 1; \ } \ - ++lst_ok; \ } while (0) #define LS_CAT2(a, b) a##b #define LS_CAT(a, b) LS_CAT2(a, b) @@ -217,7 +213,6 @@ extern lst_func* lst_funcs; extern int lst_n; extern int lst_cap; extern int lst_fail; -extern int lst_ok; void lst_reg(lst_func f); @@ -229,7 +224,6 @@ lst_func* lst_funcs; int lst_n; int lst_cap; int lst_fail = 0; -int lst_ok = 0; void lst_reg(lst_func f) { if (lst_n == lst_cap) { @@ -276,8 +270,8 @@ static int ls_test_main(int argc, char** argv) { } end: - fprintf(stderr, "%d succeeded, %d failed, %d total\n", lst_ok, lst_fail, - lst_ok + lst_fail); + fprintf(stderr, "%d succeeded, %d failed, %d total\n", lst_n - lst_fail, + lst_fail, lst_n); free(lst_funcs); if (lst_fail > 0) { diff --git a/tests/tests.c b/tests/tests.c index 450c6bd..8b22e06 100644 --- a/tests/tests.c +++ b/tests/tests.c @@ -1,6 +1,22 @@ +#include <stdint.h> +#include <limits.h> #define LS_TEST_IMPLEMENTATION #include "ls_test.h" +int fail_alloc = 0; + +void* test_realloc(void* p, size_t size) { + if (fail_alloc) { + return NULL; + } + return realloc(p, size); +} + +/* this is also set in the Makefile because of the way this is built for tests. + * It requires a bit of magic because of the way we do things. + */ +#define LS_REALLOC test_realloc + #include "ls_args.h" TEST_CASE(basic_args) { @@ -12,10 +28,201 @@ TEST_CASE(basic_args) { int argc = sizeof(argv) / sizeof(*argv) - 1; ls_args_init(&args); - ls_arg_bool(&args, &help, "h", "help", "Provides help", 0); - ls_arg_bool(&args, &test, "t", "test", "A test argument", 0); - ls_arg_bool(&args, &no, "n", "nope", "An argument that isn't present", 0); - ASSERT(ls_args_parse(&args, argc, argv)); + ls_args_bool(&args, &help, "h", "help", "Provides help", 0); + ls_args_bool(&args, &test, "t", "test", "A test argument", 0); + ls_args_bool(&args, &no, "n", "nope", "An argument that isn't present", 0); + if (!ls_args_parse(&args, argc, argv)) { + printf("Error: %s\n", args.last_error); + ASSERT(!"ls_args_parse failed"); + } + ASSERT_EQ(help, 1, "%d"); + ASSERT_EQ(test, 1, "%d"); + ASSERT_EQ(no, 0, "%d"); + ls_args_free(&args); + return 0; +} + +TEST_CASE(basic_args_only_short) { + int help = 0; + int test = 0; + int no = 0; + ls_args args; + char* argv[] = { "./hello", "-h", "-t", NULL }; + int argc = sizeof(argv) / sizeof(*argv) - 1; + + ls_args_init(&args); + ls_args_bool(&args, &help, "h", NULL, "Provides help", 0); + ls_args_bool(&args, &test, "t", NULL, "A test argument", 0); + ls_args_bool(&args, &no, "n", NULL, "An argument that isn't present", 0); + if (!ls_args_parse(&args, argc, argv)) { + printf("Error: %s\n", args.last_error); + ASSERT(!"ls_args_parse failed"); + } + ASSERT_EQ(help, 1, "%d"); + ASSERT_EQ(test, 1, "%d"); + ASSERT_EQ(no, 0, "%d"); + ls_args_free(&args); + return 0; +} + +TEST_CASE(basic_args_only_long) { + int help = 0; + int test = 0; + int no = 0; + ls_args args; + char* argv[] = { "./hello", "--help", "--test", NULL }; + int argc = sizeof(argv) / sizeof(*argv) - 1; + + ls_args_init(&args); + ls_args_bool(&args, &help, NULL, "help", "Provides help", 0); + ls_args_bool(&args, &test, NULL, "test", "A test argument", 0); + ls_args_bool(&args, &no, NULL, "nope", "An argument that isn't present", 0); + if (!ls_args_parse(&args, argc, argv)) { + printf("Error: %s\n", args.last_error); + ASSERT(!"ls_args_parse failed"); + } + ASSERT_EQ(help, 1, "%d"); + ASSERT_EQ(test, 1, "%d"); + ASSERT_EQ(no, 0, "%d"); + ls_args_free(&args); + return 0; +} + +TEST_CASE(basic_args_short_combined) { + int help = 0; + int test = 0; + int no = 0; + ls_args args; + char* argv[] = { "./hello", "-ht", NULL }; + int argc = sizeof(argv) / sizeof(*argv) - 1; + + ls_args_init(&args); + ls_args_bool(&args, &help, "h", "help", "Provides help", 0); + ls_args_bool(&args, &test, "t", "test", "A test argument", 0); + ls_args_bool(&args, &no, "n", "nope", "An argument that isn't present", 0); + if (!ls_args_parse(&args, argc, argv)) { + printf("Error: %s\n", args.last_error); + ASSERT(!"ls_args_parse failed"); + } + ASSERT_EQ(help, 1, "%d"); + ASSERT_EQ(test, 1, "%d"); + ASSERT_EQ(no, 0, "%d"); + ls_args_free(&args); + return 0; +} + +TEST_CASE(error_invalid_argument) { + int help = 0; + ls_args args; + char* argv[] = { "./hello", "-h", "--test", NULL }; + int argc = sizeof(argv) / sizeof(*argv) - 1; + + ls_args_init(&args); + ls_args_bool(&args, &help, "h", "help", "Provides help", 0); + ASSERT(!ls_args_parse(&args, argc, argv)); + ASSERT(strcmp(args.last_error, "Invalid argument '--test'") == 0); + ls_args_free(&args); + return 0; +} + +TEST_CASE(error_expected_argument) { + const char* file = 0; + ls_args args; + int help; + char* argv[] = { "./hello", "--file", "--help", NULL }; + int argc = sizeof(argv) / sizeof(*argv) - 1; + + ls_args_init(&args); + ls_args_bool(&args, &help, "h", "help", "Provides help", 0); + ls_args_string(&args, &file, "f", "file", "File to work on", 0); + ASSERT(!ls_args_parse(&args, argc, argv)); + ASSERT(strcmp(args.last_error, "Expected argument following '--file'") == 0); + ls_args_free(&args); + return 0; +} + +TEST_CASE(error_expected_argument_last_arg) { + const char* file = 0; + ls_args args; + char* argv[] = { "./hello", "--file", NULL }; + int argc = sizeof(argv) / sizeof(*argv) - 1; + + ls_args_init(&args); + ls_args_string(&args, &file, "f", "file", "File to work on", 0); + ASSERT(!ls_args_parse(&args, argc, argv)); + ASSERT(strcmp(args.last_error, "Expected argument following '--file'") == 0); + ls_args_free(&args); + return 0; +} + +TEST_CASE(error_expected_argument_short_combined) { + const char* file = 0; + ls_args args; + int help; + char* argv[] = { "./hello", "-fh", NULL }; + int argc = sizeof(argv) / sizeof(*argv) - 1; + + ls_args_init(&args); + ls_args_bool(&args, &help, "h", "help", "Provides help", 0); + ls_args_string(&args, &file, "f", "file", "File to work on", 0); + ASSERT(!ls_args_parse(&args, argc, argv)); + ASSERT(strcmp(args.last_error, "Expected argument following '-f', instead got another argument '-h'") == 0); + ls_args_free(&args); + return 0; +} + +TEST_CASE(error_parse_fail) { + int help = 0; + ls_args args; + char* argv[] = { "./hello", "-", NULL }; + int argc = sizeof(argv) / sizeof(*argv) - 1; + + ls_args_init(&args); + ASSERT(!ls_args_parse(&args, argc, argv)); + ASSERT(strcmp(args.last_error, "Invalid argument '-'") == 0); + ls_args_free(&args); + return 0; +} + +TEST_CASE(overflow_args_cap) { + int help = 0; + int dummy = 0; + ls_args args; + int ret; + + ls_args_init(&args); + /* First allocate one arg so the structure is properly initialized */ + ret = ls_args_bool(&args, &dummy, "d", "dummy", "Dummy argument", 0); + ASSERT(ret); + /* can't have more elements, not even one, at this count */ + args.args_len = SIZE_MAX / sizeof(ls_args_arg); + args.args_cap = SIZE_MAX / sizeof(ls_args_arg); + /* Try to add an argument, which should fail due to overflow */ + ret = ls_args_bool(&args, &help, "h", "help", "Provides help", 0); + ASSERT(!ret); + ls_args_free(&args); + return 0; +} + +TEST_CASE(strip_dashes) { + int help = 0; + int test = 0; + int no = 0; + ls_args args; + char* argv[] = { "./hello", "-h", "--test", NULL }; + int argc = sizeof(argv) / sizeof(*argv) - 1; + + ls_args_init(&args); + /* the dashes are optional */ + ls_args_bool(&args, &help, "-h", "--help", "Provides help", 0); + /* you can mix them */ + ls_args_bool(&args, &test, "t", "--test", "A test argument", 0); + /* have as many as you want */ + ls_args_bool(&args, &no, "-n", "----nope", "An argument that isn't present", 0); + if (!ls_args_parse(&args, argc, argv)) { + printf("Error: %s\n", args.last_error); + ASSERT(!"ls_args_parse failed"); + } ASSERT_EQ(help, 1, "%d"); ASSERT_EQ(test, 1, "%d"); ASSERT_EQ(no, 0, "%d"); @@ -23,18 +230,81 @@ TEST_CASE(basic_args) { return 0; } +TEST_CASE(alloc_fail) { + int help = 0; + ls_args args; + char* argv[] = { "./hello", "-", NULL }; + int argc = sizeof(argv) / sizeof(*argv) - 1; + int ret; + + ls_args_init(&args); + ASSERT_EQ(args.args_len, 0, "%uz"); + /* deliberately fail the allocation here */ + fail_alloc = 1; + /* if the allocation fails, this fails */ + ret = ls_args_bool(&args, &help, "h", "help", "Provides help", 0); + fail_alloc = 0; + ASSERT(!ret); + ASSERT(strcmp(args.last_error, "Allocation failure") == 0); + /* there is no documented error state for this; we simply fail to add the + * argument? */ + ASSERT_EQ(args.args_len, 0, "%uz"); + ls_args_free(&args); + return 0; +} + +TEST_CASE(error_parse_fail_empty) { + int help = 0; + ls_args args; + char* argv[] = { "./hello", "", NULL }; + int argc = sizeof(argv) / sizeof(*argv) - 1; + + ls_args_init(&args); + ASSERT(!ls_args_parse(&args, argc, argv)); + ASSERT(strcmp(args.last_error, "Invalid argument ''") == 0); + ls_args_free(&args); + return 0; +} + +TEST_CASE(error_parse_ignore_double_dash) { + int help = 0; + ls_args args; + char* argv[] = { "./hello", "--", NULL }; + int argc = sizeof(argv) / sizeof(*argv) - 1; + + ls_args_init(&args); + ASSERT(ls_args_parse(&args, argc, argv)); + ls_args_free(&args); + return 0; +} + +TEST_CASE(error_invalid_argument_short) { + int help = 0; + ls_args args; + char* argv[] = { "./hello", "-h", "-t", "-h", NULL }; + int argc = sizeof(argv) / sizeof(*argv) - 1; + + ls_args_init(&args); + ls_args_bool(&args, &help, "h", "help", "Provides help", 0); + ASSERT(!ls_args_parse(&args, argc, argv)); + ASSERT(strcmp(args.last_error, "Invalid argument '-t'") == 0); + ls_args_free(&args); + return 0; +} + TEST_CASE(string_args) { const char* input = NULL; const char* output = NULL; int verbose = 0; ls_args args; - char* argv[] = { "./program", "--input", "file.txt", "-o", "output.txt", "-v", NULL }; + char* argv[] = { "./program", "--input", "file.txt", "-o", "output.txt", + "-v", NULL }; int argc = sizeof(argv) / sizeof(*argv) - 1; ls_args_init(&args); - ls_arg_string(&args, &input, "i", "input", "Input file path", 0); - ls_arg_string(&args, &output, "o", "output", "Output file path", 0); - ls_arg_bool(&args, &verbose, "v", "verbose", "Verbose output", 0); + ls_args_string(&args, &input, "i", "input", "Input file path", 0); + ls_args_string(&args, &output, "o", "output", "Output file path", 0); + ls_args_bool(&args, &verbose, "v", "verbose", "Verbose output", 0); ASSERT(ls_args_parse(&args, argc, argv)); ASSERT(strcmp(input, "file.txt") == 0); ASSERT(strcmp(output, "output.txt") == 0); |
