diff --git a/Makefile b/Makefile index 4dca0f2..71eff7c 100644 --- a/Makefile +++ b/Makefile @@ -55,7 +55,7 @@ check: ## Static analysis --check-level=exhaustive --project=$(BUILD_DIR)/compile_commands.json \ --suppress=missingIncludeSystem -i$(BUILD_DIR) -check-all: format lint check ## Run all checks +check-all: test format lint check ## Run all checks fix: ## Fix code formatting and linting issues @test -n "$(CLANG_FORMAT)" || { echo "error: clang-format not found"; exit 1; } diff --git a/include/tl_flag.h b/include/tl_flag.h index 83d07a6..e463d5a 100644 --- a/include/tl_flag.h +++ b/include/tl_flag.h @@ -44,10 +44,12 @@ typedef struct { /** * @brief Parses the given command line arguments. * - * Parses argv into flags. A flag is anything starting with "--". It can carry - * a value written as --name=value, or as --name value in the next entry. - * A bare "--" ends flag parsing; everything after it is a positional, even if - * it starts with dashes. Any previously parsed state is thrown away first. + * Parses argv into flags and positionals. A flag is anything starting + * with "-" or "--" (e.g. "-h", "--help"). It can carry a value written as + * --name=value, or as --name value in the next entry. A bare "-" is a + * positional. A bare "--" ends flag parsing; everything after it is a + * positional, even if it starts with dashes. Any previously parsed state + * is thrown away first. * * @param argc The number of command line arguments. * @param argv The command line arguments. @@ -124,8 +126,8 @@ const char *tl_get_flag_at(const char *flag, size_t index); /** * @brief Returns the number of positional arguments. * - * Positionals are bare arguments (not starting with `--`) and everything - * after a bare `--` terminator, in the order they appeared. + * Positionals are bare arguments (not starting with `-` or `--`) and + * everything after a bare `--` terminator, in the order they appeared. * * @return The positional argument count. */ diff --git a/src/tl_flag.c b/src/tl_flag.c index 8d3d2de..9165f46 100644 --- a/src/tl_flag.c +++ b/src/tl_flag.c @@ -13,17 +13,39 @@ static char *line_buf = NULL; static char **line_tokens = NULL; /** - * @brief Returns whether the token is a long flag (starts with "--" and has content). + * @brief Returns whether the token is a flag. + * + * A flag starts with "-" or "--" and is not a bare "-" or "--". + * A bare "-" is not a flag (it's a common stdin placeholder). + * A bare "--" is the positional terminator and is handled separately. */ -static bool is_long_flag(const char *s) { - return s != NULL && s[0] == '-' && s[1] == '-' && s[2] != '\0'; +static bool is_flag(const char *s) { + if (s == NULL || s[0] != '-' || s[1] == '\0') { + return false; + } + if (s[1] == '-' && s[2] == '\0') { + return false; + } + return true; } /** * @brief Returns whether the token is the bare "--" terminator. */ static bool is_dash_dash(const char *s) { - return s != NULL && s[0] == '-' && s[1] == '-' && s[2] == '\0'; + if (s == NULL) { + return false; + } + if (s[0] != '-') { + return false; + } + if (s[1] != '-') { + return false; + } + if (s[2] != '\0') { + return false; + } + return true; } /** @@ -40,7 +62,7 @@ static bool flag_matches(const tl_flag_t *f, const char *name, size_t name_len) * @brief Fills the flag and positional tables from a token list. * * The first token is the program name and is skipped. The rest are - * sorted into flags (anything starting with "--") and positionals + * sorted into flags (anything starting with "-" or "--") and positionals * (everything else, plus anything after a bare "--"). */ static bool parse_tokens(char **tokens, int count) { @@ -70,8 +92,8 @@ static bool parse_tokens(char **tokens, int count) { after_dd = true; continue; } - // Long flag - if (is_long_flag(tok)) { + // Flag + if (is_flag(tok)) { char *eq = strchr(tok, '='); if (eq) { flags[flag_count].name = tok; @@ -81,7 +103,7 @@ static bool parse_tokens(char **tokens, int count) { const char *value = NULL; // Consume the next token as the value if it is not another flag // and not the "--" terminator - if (i + 1 < count && !is_long_flag(tokens[i + 1]) && !is_dash_dash(tokens[i + 1])) { + if (i + 1 < count && !is_flag(tokens[i + 1]) && !is_dash_dash(tokens[i + 1])) { value = tokens[i + 1]; i++; } @@ -98,6 +120,43 @@ static bool parse_tokens(char **tokens, int count) { return true; } +/** + * @brief Reads one token from `line` starting at `*i` into `line_buf` at `*bi`. + * + * Stops at unquoted whitespace or end of line. Writes the NUL terminator. + * Returns true on success, false if a quoted string was never closed. + */ +static bool read_one_token(const char *line, size_t len, size_t *i, size_t *bi) { + bool in_quote = false; + while (*i < len) { + char c = line[*i]; + if (!in_quote && (c == ' ' || c == '\t')) { + break; + } + if (c == '"') { + if (in_quote) { + in_quote = false; + } else { + in_quote = true; + } + (*i)++; + continue; + } + if (c == '\\' && *i + 1 < len) { + line_buf[(*bi)++] = line[*i + 1]; + *i += 2; + continue; + } + line_buf[(*bi)++] = c; + (*i)++; + } + if (in_quote) { + return false; + } + line_buf[(*bi)++] = '\0'; + return true; +} + /** * @brief Splits a command line string into tokens stored in line_tokens. * @@ -131,31 +190,10 @@ static int tokenize_line(const char *line) { if (i >= len) { break; } - // Start a new token at the current buffer position line_tokens[n++] = &line_buf[bi]; - bool in_quote = false; - while (i < len) { - char c = line[i]; - if (!in_quote && (c == ' ' || c == '\t')) { - break; - } - if (c == '"') { - in_quote = in_quote ? false : true; - i++; - continue; - } - if (c == '\\' && i + 1 < len) { - line_buf[bi++] = line[i + 1]; - i += 2; - continue; - } - line_buf[bi++] = c; - i++; - } - if (in_quote) { - return -1; // unterminated quoted string + if (!read_one_token(line, len, &i, &bi)) { + return -1; } - line_buf[bi++] = '\0'; } return (int)n; } diff --git a/tests/unit/tl_flag_test.c b/tests/unit/tl_flag_test.c index e13cfe9..31dbf71 100644 --- a/tests/unit/tl_flag_test.c +++ b/tests/unit/tl_flag_test.c @@ -141,6 +141,150 @@ static void test_tl_parse_line_unterminated(void) { TEST_ASSERT_FALSE(tl_parse_line("program --foo \"unterminated")); } +static void test_tl_short_flag(void) { + char *argv[] = {"program", "-h"}; + tl_parse_args(2, argv); + TEST_ASSERT_TRUE(tl_lookup_flag("-h")); + TEST_ASSERT_NULL(tl_get_flag("-h")); + TEST_ASSERT_EQUAL_UINT(0, tl_count_positional()); +} + +static void test_tl_short_flag_value(void) { + char *argv[] = {"program", "-o", "out.txt", "-v"}; + tl_parse_args(4, argv); + TEST_ASSERT_EQUAL_STRING("out.txt", tl_get_flag("-o")); + TEST_ASSERT_TRUE(tl_lookup_flag("-v")); + TEST_ASSERT_NULL(tl_get_flag("-v")); +} + +static void test_tl_short_flag_equals(void) { + char *argv[] = {"program", "-o=out.txt"}; + tl_parse_args(2, argv); + TEST_ASSERT_EQUAL_STRING("out.txt", tl_get_flag("-o")); +} + +static void test_tl_bare_dash_is_positional(void) { + char *argv[] = {"program", "-"}; + tl_parse_args(2, argv); + TEST_ASSERT_FALSE(tl_lookup_flag("-")); + TEST_ASSERT_EQUAL_UINT(1, tl_count_positional()); + TEST_ASSERT_EQUAL_STRING("-", tl_get_positional(0)); +} + +static void test_tl_short_flag_exact_match(void) { + char *argv[] = {"program", "-help"}; + tl_parse_args(2, argv); + TEST_ASSERT_FALSE(tl_lookup_flag("-h")); + TEST_ASSERT_NULL(tl_get_flag("-h")); + TEST_ASSERT_TRUE(tl_lookup_flag("-help")); +} + +static void test_tl_short_repeated_boolean(void) { + char *argv[] = {"program", "-v", "-v", "-v"}; + tl_parse_args(4, argv); + TEST_ASSERT_EQUAL_UINT(3, tl_count_flag("-v")); + TEST_ASSERT_NULL(tl_get_flag_at("-v", 0)); + TEST_ASSERT_NULL(tl_get_flag_at("-v", 1)); + TEST_ASSERT_NULL(tl_get_flag_at("-v", 2)); +} + +static void test_tl_short_repeated_mixed(void) { + char *argv[] = {"program", "-o=a", "-o", "b", "-o=c"}; + tl_parse_args(5, argv); + TEST_ASSERT_EQUAL_UINT(3, tl_count_flag("-o")); + TEST_ASSERT_EQUAL_STRING("a", tl_get_flag_at("-o", 0)); + TEST_ASSERT_EQUAL_STRING("b", tl_get_flag_at("-o", 1)); + TEST_ASSERT_EQUAL_STRING("c", tl_get_flag_at("-o", 2)); +} + +static void test_tl_short_adjacent(void) { + char *argv[] = {"program", "-a", "x", "-b", "y"}; + tl_parse_args(5, argv); + TEST_ASSERT_EQUAL_STRING("x", tl_get_flag("-a")); + TEST_ASSERT_EQUAL_STRING("y", tl_get_flag("-b")); +} + +static void test_tl_short_trailing_boolean(void) { + char *argv[] = {"program", "-o", "-v"}; + tl_parse_args(3, argv); + TEST_ASSERT_TRUE(tl_lookup_flag("-o")); + TEST_ASSERT_NULL(tl_get_flag("-o")); + TEST_ASSERT_TRUE(tl_lookup_flag("-v")); + TEST_ASSERT_NULL(tl_get_flag("-v")); +} + +static void test_tl_short_value_is_bare_dash(void) { + char *argv[] = {"program", "-o", "-"}; + tl_parse_args(3, argv); + TEST_ASSERT_EQUAL_STRING("-", tl_get_flag("-o")); + TEST_ASSERT_EQUAL_UINT(0, tl_count_positional()); +} + +static void test_tl_short_long_mixed(void) { + char *argv[] = {"program", "-v", "--name=foo", "-o", "out", "--flag"}; + tl_parse_args(6, argv); + TEST_ASSERT_TRUE(tl_lookup_flag("-v")); + TEST_ASSERT_EQUAL_STRING("foo", tl_get_flag("--name")); + TEST_ASSERT_EQUAL_STRING("out", tl_get_flag("-o")); + TEST_ASSERT_TRUE(tl_lookup_flag("--flag")); + TEST_ASSERT_NULL(tl_get_flag("--flag")); +} + +static void test_tl_short_followed_by_long(void) { + char *argv[] = {"program", "-o", "--other"}; + tl_parse_args(3, argv); + TEST_ASSERT_TRUE(tl_lookup_flag("-o")); + TEST_ASSERT_NULL(tl_get_flag("-o")); + TEST_ASSERT_TRUE(tl_lookup_flag("--other")); +} + +static void test_tl_positional_dashdash_trailing_empty(void) { + char *argv[] = {"program", "--foo", "--"}; + tl_parse_args(3, argv); + TEST_ASSERT_TRUE(tl_lookup_flag("--foo")); + TEST_ASSERT_NULL(tl_get_flag("--foo")); + TEST_ASSERT_EQUAL_UINT(0, tl_count_positional()); +} + +static void test_tl_positional_second_dashdash_is_positional(void) { + char *argv[] = {"program", "--", "a", "--", "b"}; + tl_parse_args(5, argv); + TEST_ASSERT_EQUAL_UINT(3, tl_count_positional()); + TEST_ASSERT_EQUAL_STRING("a", tl_get_positional(0)); + TEST_ASSERT_EQUAL_STRING("--", tl_get_positional(1)); + TEST_ASSERT_EQUAL_STRING("b", tl_get_positional(2)); +} + +static void test_tl_positional_mixed_short_long(void) { + char *argv[] = {"program", "pos1", "-v", "--name", "foo", "pos2", "--", "-x", "--y"}; + tl_parse_args(9, argv); + TEST_ASSERT_TRUE(tl_lookup_flag("-v")); + TEST_ASSERT_EQUAL_STRING("foo", tl_get_flag("--name")); + TEST_ASSERT_FALSE(tl_lookup_flag("-x")); + TEST_ASSERT_FALSE(tl_lookup_flag("--y")); + TEST_ASSERT_EQUAL_UINT(4, tl_count_positional()); + TEST_ASSERT_EQUAL_STRING("pos1", tl_get_positional(0)); + TEST_ASSERT_EQUAL_STRING("pos2", tl_get_positional(1)); + TEST_ASSERT_EQUAL_STRING("-x", tl_get_positional(2)); + TEST_ASSERT_EQUAL_STRING("--y", tl_get_positional(3)); +} + +static void test_tl_positional_only(void) { + char *argv[] = {"program", "a", "b", "c"}; + tl_parse_args(4, argv); + TEST_ASSERT_EQUAL_UINT(0, tl_count_flag("--any")); + TEST_ASSERT_EQUAL_UINT(3, tl_count_positional()); + TEST_ASSERT_EQUAL_STRING("a", tl_get_positional(0)); + TEST_ASSERT_EQUAL_STRING("b", tl_get_positional(1)); + TEST_ASSERT_EQUAL_STRING("c", tl_get_positional(2)); +} + +static void test_tl_positional_dashdash_only(void) { + char *argv[] = {"program", "--"}; + tl_parse_args(2, argv); + TEST_ASSERT_EQUAL_UINT(0, tl_count_positional()); +} + static void test_tl_parse_line_quoted_positional(void) { TEST_ASSERT_TRUE(tl_parse_line("prog \"first pos\" --flag v -- \"after dd\" plain")); TEST_ASSERT_EQUAL_STRING("v", tl_get_flag("--flag")); @@ -150,6 +294,180 @@ static void test_tl_parse_line_quoted_positional(void) { TEST_ASSERT_EQUAL_STRING("plain", tl_get_positional(2)); } +static void test_tl_long_empty_value(void) { + char *argv[] = {"program", "--foo="}; + tl_parse_args(2, argv); + TEST_ASSERT_TRUE(tl_lookup_flag("--foo")); + TEST_ASSERT_EQUAL_STRING("", tl_get_flag("--foo")); +} + +static void test_tl_long_value_contains_equals(void) { + char *argv[] = {"program", "--foo=a=b=c"}; + tl_parse_args(2, argv); + TEST_ASSERT_EQUAL_STRING("a=b=c", tl_get_flag("--foo")); +} + +static void test_tl_long_space_value_before_terminator(void) { + char *argv[] = {"program", "--foo", "val", "--", "pos"}; + tl_parse_args(5, argv); + TEST_ASSERT_EQUAL_STRING("val", tl_get_flag("--foo")); + TEST_ASSERT_EQUAL_UINT(1, tl_count_positional()); + TEST_ASSERT_EQUAL_STRING("pos", tl_get_positional(0)); +} + +static void test_tl_short_empty_value(void) { + char *argv[] = {"program", "-o="}; + tl_parse_args(2, argv); + TEST_ASSERT_TRUE(tl_lookup_flag("-o")); + TEST_ASSERT_EQUAL_STRING("", tl_get_flag("-o")); +} + +static void test_tl_short_multichar_name(void) { + char *argv[] = {"program", "-xvf", "archive.tar"}; + tl_parse_args(3, argv); + TEST_ASSERT_TRUE(tl_lookup_flag("-xvf")); + TEST_ASSERT_EQUAL_STRING("archive.tar", tl_get_flag("-xvf")); + TEST_ASSERT_FALSE(tl_lookup_flag("-x")); + TEST_ASSERT_FALSE(tl_lookup_flag("-v")); + TEST_ASSERT_FALSE(tl_lookup_flag("-f")); +} + +static void test_tl_terminator_at_start(void) { + char *argv[] = {"program", "--", "--foo", "bar"}; + tl_parse_args(4, argv); + TEST_ASSERT_FALSE(tl_lookup_flag("--foo")); + TEST_ASSERT_EQUAL_UINT(2, tl_count_positional()); + TEST_ASSERT_EQUAL_STRING("--foo", tl_get_positional(0)); + TEST_ASSERT_EQUAL_STRING("bar", tl_get_positional(1)); +} + +static void test_tl_null_flag_argument(void) { + char *argv[] = {"program", "--foo=bar"}; + tl_parse_args(2, argv); + TEST_ASSERT_FALSE(tl_lookup_flag(NULL)); + TEST_ASSERT_NULL(tl_get_flag(NULL)); + TEST_ASSERT_EQUAL_UINT(0, tl_count_flag(NULL)); + TEST_ASSERT_NULL(tl_get_flag_at(NULL, 0)); +} + +static void test_tl_empty_argv(void) { + char *argv[] = {"program"}; + tl_parse_args(1, argv); + TEST_ASSERT_FALSE(tl_lookup_flag("--anything")); + TEST_ASSERT_NULL(tl_get_flag("--anything")); + TEST_ASSERT_EQUAL_UINT(0, tl_count_flag("--anything")); + TEST_ASSERT_EQUAL_UINT(0, tl_count_positional()); + TEST_ASSERT_NULL(tl_get_positional(0)); +} + +static void test_tl_reparse_clears_previous(void) { + char *argv1[] = {"program", "--old=1", "oldpos"}; + tl_parse_args(3, argv1); + TEST_ASSERT_EQUAL_STRING("1", tl_get_flag("--old")); + TEST_ASSERT_EQUAL_UINT(1, tl_count_positional()); + + char *argv2[] = {"program", "--new=2"}; + tl_parse_args(2, argv2); + TEST_ASSERT_FALSE(tl_lookup_flag("--old")); + TEST_ASSERT_EQUAL_STRING("2", tl_get_flag("--new")); + TEST_ASSERT_EQUAL_UINT(0, tl_count_positional()); +} + +static void test_tl_reparse_line_after_args(void) { + char *argv[] = {"program", "--first=1"}; + tl_parse_args(2, argv); + TEST_ASSERT_EQUAL_STRING("1", tl_get_flag("--first")); + + TEST_ASSERT_TRUE(tl_parse_line("program --second=2")); + TEST_ASSERT_FALSE(tl_lookup_flag("--first")); + TEST_ASSERT_EQUAL_STRING("2", tl_get_flag("--second")); +} + +static void test_tl_free_args_idempotent(void) { + tl_free_args(); + tl_free_args(); + char *argv[] = {"program", "--foo"}; + tl_parse_args(2, argv); + tl_free_args(); + tl_free_args(); + TEST_ASSERT_FALSE(tl_lookup_flag("--foo")); +} + +static void test_tl_count_flag_absent(void) { + char *argv[] = {"program", "--foo"}; + tl_parse_args(2, argv); + TEST_ASSERT_EQUAL_UINT(0, tl_count_flag("--missing")); + TEST_ASSERT_NULL(tl_get_flag_at("--missing", 0)); + TEST_ASSERT_NULL(tl_get_flag_at("--foo", 5)); +} + +static void test_tl_parse_line_empty(void) { + TEST_ASSERT_TRUE(tl_parse_line("")); + TEST_ASSERT_EQUAL_UINT(0, tl_count_positional()); +} + +static void test_tl_parse_line_whitespace_only(void) { + TEST_ASSERT_TRUE(tl_parse_line(" \t ")); + TEST_ASSERT_EQUAL_UINT(0, tl_count_positional()); +} + +static void test_tl_parse_line_program_only(void) { + TEST_ASSERT_TRUE(tl_parse_line("program")); + TEST_ASSERT_EQUAL_UINT(0, tl_count_positional()); + TEST_ASSERT_FALSE(tl_lookup_flag("--anything")); +} + +static void test_tl_parse_line_multiple_spaces(void) { + TEST_ASSERT_TRUE(tl_parse_line("prog --foo=1\t\t--bar val")); + TEST_ASSERT_EQUAL_STRING("1", tl_get_flag("--foo")); + TEST_ASSERT_EQUAL_STRING("val", tl_get_flag("--bar")); +} + +static void test_tl_parse_line_empty_quoted_value(void) { + TEST_ASSERT_TRUE(tl_parse_line("program --foo \"\"")); + TEST_ASSERT_TRUE(tl_lookup_flag("--foo")); + TEST_ASSERT_EQUAL_STRING("", tl_get_flag("--foo")); +} + +static void test_tl_parse_line_escaped_space(void) { + TEST_ASSERT_TRUE(tl_parse_line("program --foo bar\\ baz")); + TEST_ASSERT_EQUAL_STRING("bar baz", tl_get_flag("--foo")); +} + +static void test_tl_parse_line_trailing_backslash(void) { + TEST_ASSERT_TRUE(tl_parse_line("program --foo bar\\")); + TEST_ASSERT_EQUAL_STRING("bar\\", tl_get_flag("--foo")); +} + +static void test_tl_parse_line_double_backslash(void) { + TEST_ASSERT_TRUE(tl_parse_line("program --foo \"a\\\\b\"")); + TEST_ASSERT_EQUAL_STRING("a\\b", tl_get_flag("--foo")); +} + +static void test_tl_negative_number_value(void) { + // Space form: -5 is treated as its own flag. Use the = form for negatives. + char *argv1[] = {"program", "--count", "-5"}; + tl_parse_args(3, argv1); + TEST_ASSERT_TRUE(tl_lookup_flag("--count")); + TEST_ASSERT_NULL(tl_get_flag("--count")); + TEST_ASSERT_TRUE(tl_lookup_flag("-5")); + + // Equals form: unambiguous, works as expected. + char *argv2[] = {"program", "--count=-5"}; + tl_parse_args(2, argv2); + TEST_ASSERT_EQUAL_STRING("-5", tl_get_flag("--count")); +} + +static void test_tl_parse_args_null_argv(void) { + tl_parse_args(0, NULL); + TEST_ASSERT_EQUAL_UINT(0, tl_count_positional()); + TEST_ASSERT_FALSE(tl_lookup_flag("--anything")); + + tl_parse_args(5, NULL); + TEST_ASSERT_EQUAL_UINT(0, tl_count_positional()); + TEST_ASSERT_FALSE(tl_lookup_flag("--anything")); +} + int main(void) { UNITY_BEGIN(); @@ -170,7 +488,46 @@ int main(void) { RUN_TEST(test_tl_parse_line_escape); RUN_TEST(test_tl_parse_line_full); RUN_TEST(test_tl_parse_line_unterminated); + RUN_TEST(test_tl_short_flag); + RUN_TEST(test_tl_short_flag_value); + RUN_TEST(test_tl_short_flag_equals); + RUN_TEST(test_tl_bare_dash_is_positional); + RUN_TEST(test_tl_short_flag_exact_match); + RUN_TEST(test_tl_short_repeated_boolean); + RUN_TEST(test_tl_short_repeated_mixed); + RUN_TEST(test_tl_short_adjacent); + RUN_TEST(test_tl_short_trailing_boolean); + RUN_TEST(test_tl_short_value_is_bare_dash); + RUN_TEST(test_tl_short_long_mixed); + RUN_TEST(test_tl_short_followed_by_long); + RUN_TEST(test_tl_positional_dashdash_trailing_empty); + RUN_TEST(test_tl_positional_second_dashdash_is_positional); + RUN_TEST(test_tl_positional_mixed_short_long); + RUN_TEST(test_tl_positional_only); + RUN_TEST(test_tl_positional_dashdash_only); RUN_TEST(test_tl_parse_line_quoted_positional); + RUN_TEST(test_tl_long_empty_value); + RUN_TEST(test_tl_long_value_contains_equals); + RUN_TEST(test_tl_long_space_value_before_terminator); + RUN_TEST(test_tl_short_empty_value); + RUN_TEST(test_tl_short_multichar_name); + RUN_TEST(test_tl_terminator_at_start); + RUN_TEST(test_tl_null_flag_argument); + RUN_TEST(test_tl_empty_argv); + RUN_TEST(test_tl_reparse_clears_previous); + RUN_TEST(test_tl_reparse_line_after_args); + RUN_TEST(test_tl_free_args_idempotent); + RUN_TEST(test_tl_count_flag_absent); + RUN_TEST(test_tl_parse_line_empty); + RUN_TEST(test_tl_parse_line_whitespace_only); + RUN_TEST(test_tl_parse_line_program_only); + RUN_TEST(test_tl_parse_line_multiple_spaces); + RUN_TEST(test_tl_parse_line_empty_quoted_value); + RUN_TEST(test_tl_parse_line_escaped_space); + RUN_TEST(test_tl_parse_line_trailing_backslash); + RUN_TEST(test_tl_parse_line_double_backslash); + RUN_TEST(test_tl_negative_number_value); + RUN_TEST(test_tl_parse_args_null_argv); return UNITY_END(); }