aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorLion Kortlepel <[email protected]>2026-01-22 23:18:16 +0100
committerLion Kortlepel <[email protected]>2026-01-22 23:18:16 +0100
commit2d2be7e2b38031f7cd826f78543b18a287423ad7 (patch)
tree2bf0eba1995000e8d95cffae4101486541ce6eeb /tests
parent36fdeca43eab4439a117d4c912f87e704eaa9cd5 (diff)
downloadargs-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.h16
-rw-r--r--tests/tests.c286
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);