aboutsummaryrefslogtreecommitdiff
path: root/tests/tests.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/tests.c')
-rw-r--r--tests/tests.c252
1 files changed, 244 insertions, 8 deletions
diff --git a/tests/tests.c b/tests/tests.c
index 6a7b4b7..9b9007e 100644
--- a/tests/tests.c
+++ b/tests/tests.c
@@ -3,10 +3,15 @@
#define LS_TEST_IMPLEMENTATION
#include "ls_test.h"
-int fail_alloc = 0;
+int fail_alloc_once = 0;
+int alloc_limit = -1;
void* test_realloc(void* p, size_t size) {
- if (fail_alloc) {
+ if (fail_alloc_once) {
+ fail_alloc_once = 0;
+ return NULL;
+ }
+ if (alloc_limit != -1 && (int)size > alloc_limit) {
return NULL;
}
return realloc(p, size);
@@ -70,15 +75,246 @@ TEST_CASE(basic_args_with_unused_positionals) {
return 0;
}
+TEST_CASE(help_output_no_options) {
+ ls_args args;
+ const char* infile = NULL;
+ char* help_str;
+
+ ls_args_init(&args);
+ ls_args_pos_string(&args, &infile, "Input file", 0);
+
+ help_str = ls_args_help(&args);
+ ASSERT(help_str != NULL);
+ ASSERT_STR_EQ(args.last_error, "Success");
+
+ /* [OPTION] should NOT be present */
+ ASSERT(!strstr(help_str, "[OPTION]"));
+
+ /* "Options:" should NOT be present */
+ ASSERT(!strstr(help_str, "Options:"));
+
+ /* The positional argument should be present */
+ ASSERT(strstr(help_str, "[Input file]") || strstr(help_str, "<Input file>"));
+
+ ls_args_free(&args);
+ return 0;
+}
+
+TEST_CASE(huge_description) {
+ int help = 0;
+ ls_args args;
+ int i;
+ char* help_str;
+ /* Create a very large description string */
+ enum { DESC_SIZE = 8192 };
+ char* huge_desc = (char*)LS_REALLOC(NULL, DESC_SIZE + 1);
+ ASSERT(huge_desc != NULL);
+ for (i = 0; i < DESC_SIZE; ++i) {
+ huge_desc[i] = 'A' + (i % 26);
+ }
+ huge_desc[DESC_SIZE] = '\0';
+
+ ls_args_init(&args);
+ ls_args_bool(&args, &help, "h", "help", huge_desc, 0);
+
+ help_str = ls_args_help(&args);
+ ASSERT(help_str != NULL);
+ ASSERT_STR_EQ(args.last_error, "Success");
+ /* The huge description should appear in the help output */
+ ASSERT(strstr(help_str, huge_desc));
+
+ LS_FREE(huge_desc);
+ ls_args_free(&args);
+ return 0;
+}
+
+TEST_CASE(help_output_basic) {
+ int help = 0;
+ const char* infile = NULL;
+ const char* outfile = "out.txt";
+ ls_args args;
+ char* help_str;
+
+ ls_args_init(&args);
+ ls_args_bool(&args, &help, "h", "help", "Provides help", 0);
+ ls_args_string(&args, &outfile, "o", "out",
+ "Specify the outfile, default 'out.txt'", 0);
+ ls_args_pos_string(&args, &infile, "Input file", 0);
+
+ help_str = ls_args_help(&args);
+ ASSERT(help_str != NULL);
+ ASSERT_STR_EQ(args.last_error, "Success");
+
+ ASSERT(strstr(help_str, "-h"));
+ ASSERT(strstr(help_str, "--help"));
+ ASSERT(strstr(help_str, "-o"));
+ ASSERT(strstr(help_str, "--out"));
+
+ ASSERT(strstr(help_str, "Provides help"));
+ ASSERT(strstr(help_str, "Specify the outfile"));
+
+ ASSERT(strstr(help_str, "[OPTION]"));
+ ASSERT(strstr(help_str, "[Input file]"));
+
+ ASSERT(strstr(help_str, "default 'out.txt'"));
+
+ ASSERT(strstr(help_str, "Input file"));
+
+ ASSERT(strstr(help_str, "-h"));
+ ASSERT(strstr(help_str, "--help"));
+ ASSERT(strstr(help_str, "-o"));
+ ASSERT(strstr(help_str, "--out"));
+
+ ls_args_free(&args);
+ return 0;
+}
+
+TEST_CASE(help_output_basic_required_pos) {
+ int help = 0;
+ const char* infile = NULL;
+ const char* outfile = "out.txt";
+ ls_args args;
+ char* help_str;
+
+ ls_args_init(&args);
+ ls_args_bool(&args, &help, "h", "help", "Provides help", 0);
+ ls_args_string(&args, &outfile, "o", "out",
+ "Specify the outfile, default 'out.txt'", 0);
+ ls_args_pos_string(&args, &infile, "Input file", LS_ARGS_REQUIRED);
+
+ help_str = ls_args_help(&args);
+ ASSERT(help_str != NULL);
+ ASSERT_STR_EQ(args.last_error, "Success");
+
+ ASSERT(strstr(help_str, "-h"));
+ ASSERT(strstr(help_str, "--help"));
+ ASSERT(strstr(help_str, "-o"));
+ ASSERT(strstr(help_str, "--out"));
+
+ ASSERT(strstr(help_str, "Provides help"));
+ ASSERT(strstr(help_str, "Specify the outfile"));
+
+ ASSERT(strstr(help_str, "[OPTION]"));
+ ASSERT(strstr(help_str, "<Input file>"));
+
+ ASSERT(strstr(help_str, "default 'out.txt'"));
+
+ ASSERT(strstr(help_str, "Input file"));
+
+ ASSERT(strstr(help_str, "-h"));
+ ASSERT(strstr(help_str, "--help"));
+ ASSERT(strstr(help_str, "-o"));
+ ASSERT(strstr(help_str, "--out"));
+
+ ls_args_free(&args);
+ return 0;
+}
+
+TEST_CASE(help_alloc_limit_sweep) {
+ int help = 0;
+ int limit;
+ const char* infile = NULL;
+ const char* outfile = "out.txt";
+ ls_args args;
+ char* help_str = NULL;
+ int succeeded = 0;
+
+ ls_args_init(&args);
+ args.help_description = "My description!";
+ ls_args_bool(&args, &help, "h", "help", "Provides help", 0);
+ ls_args_string(&args, &outfile, "o", "out",
+ "Specify the outfile, default 'out.txt'", 0);
+ ls_args_pos_string(&args, &infile, "Input file", 0);
+
+ /* Sweep alloc_limit from very small sizes upward to ensure all
+ * allocation attempts inside ls_args_help are exercised.
+ * For each limit, call ls_args_help multiple times to verify repeated failures. */
+ for (limit = 0; limit <= 8192 && !succeeded; ++limit) {
+
+ /* First attempt */
+ alloc_limit = limit;
+ help_str = ls_args_help(&args);
+ alloc_limit = -1;
+ if (help_str == NULL || strcmp(args.last_error, "Success") != 0) {
+ /* Expect allocation-related failure while we are below the needed size */
+ ASSERT_STR_EQ(args.last_error, "Allocation failure");
+ ASSERT(help_str != NULL);
+ ASSERT_STR_EQ(help_str, "Not enough memory available to generate help text.");
+
+ /* Second attempt (repeated failure path) */
+ alloc_limit = limit;
+ help_str = ls_args_help(&args);
+ alloc_limit = -1;
+ ASSERT_STR_EQ(args.last_error, "Allocation failure");
+ ASSERT(help_str != NULL);
+ ASSERT_STR_EQ(help_str, "Not enough memory available to generate help text.");
+ } else {
+ /* Success achieved at this alloc_limit; verify content */
+ succeeded = 1;
+ ASSERT(help_str != NULL);
+ ASSERT_STR_EQ(args.last_error, "Success");
+ ASSERT(strstr(help_str, "Provides help"));
+ ASSERT(strstr(help_str, "Specify the outfile"));
+ ASSERT(strstr(help_str, "Input file"));
+ }
+ }
+
+ /* Ensure we eventually succeeded in generating help text */
+ ASSERT(succeeded);
+
+ ls_args_free(&args);
+ return 0;
+}
+
+TEST_CASE(help_output_empty_description) {
+ int help = 0;
+ ls_args args;
+ char* help_str;
+
+ ls_args_init(&args);
+ ls_args_bool(&args, &help, "h", "help", "", 0);
+
+ help_str = ls_args_help(&args);
+ ASSERT(help_str != NULL);
+ ASSERT_STR_EQ(args.last_error, "Success");
+
+ /* Should show the option, but not crash or print garbage for description */
+ ASSERT(strstr(help_str, "-h"));
+ ASSERT(strstr(help_str, "--help"));
+ /* Should not print any description after the option */
+ /* Accept either a blank line or just the option itself */
+ /* There should not be any non-space character after the option on its line */
+ {
+ const char* opt_line = strstr(help_str, "-h \t--help");
+ ASSERT(opt_line != NULL);
+ /* Find the end of the line */
+ const char* end = strchr(opt_line, '\n');
+ if (end) {
+ /* Check that between the end of the option and the newline, only spaces/tabs appear */
+ const char* after = opt_line + strlen("-h \t--help");
+ while (after < end && (*after == ' ' || *after == '\t')) ++after;
+ ASSERT(after == end);
+ }
+ }
+
+ ls_args_free(&args);
+ return 0;
+}
+
+TEST_CASE(free_null) {
+ /* don't crash */
+ ls_args_free(NULL);
+ return 0;
+}
+
TEST_CASE(help_alloc_fail) {
int help = 0;
ls_args args;
char* help_str;
ls_args_init(&args);
ls_args_bool(&args, &help, "h", "help", "Provides help", 0);
- fail_alloc = 1;
+ fail_alloc_once = 1;
help_str = ls_args_help(&args);
- fail_alloc = 0;
ASSERT_STR_EQ(args.last_error, "Allocation failure");
ASSERT_STR_EQ(help_str, "Not enough memory available to generate help text.");
ls_args_free(&args);
@@ -447,10 +683,10 @@ TEST_CASE(alloc_fail) {
ls_args_init(&args);
ASSERT_EQ(args.args_len, 0, "%uz");
/* deliberately fail the allocation here */
- fail_alloc = 1;
+ fail_alloc_once = 1;
/* if the allocation fails, this fails */
ret = ls_args_bool(&args, &help, "h", "help", "Provides help", 0);
- fail_alloc = 0;
+
ASSERT(!ret);
ASSERT_STR_EQ(args.last_error, "Allocation failure");
/* there is no documented error state for this; we simply fail to add the
@@ -470,10 +706,10 @@ TEST_CASE(alloc_fail_pos_string) {
ls_args_init(&args);
ASSERT_EQ(args.args_len, 0, "%uz");
/* deliberately fail the allocation here */
- fail_alloc = 1;
+ fail_alloc_once = 1;
/* if the allocation fails, this fails */
ret = ls_args_pos_string(&args, &input, "Input file", 0);
- fail_alloc = 0;
+
ASSERT(!ret);
ASSERT_STR_EQ(args.last_error, "Allocation failure");
ASSERT_EQ(args.args_len, 0, "%uz");