diff --git a/.codex/environments/environment.toml b/.codex/environments/environment.toml new file mode 100644 index 0000000..59f9ae5 --- /dev/null +++ b/.codex/environments/environment.toml @@ -0,0 +1,12 @@ +# THIS IS AUTOGENERATED. DO NOT EDIT MANUALLY +version = 1 +name = "mise" + +[setup] +script = ''' +set -euo pipefail + +cd "${CODEX_WORKTREE_PATH:-$PWD}" + +mise trust +''' diff --git a/Makefile b/Makefile index 9d35db0..c725a0a 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ CPPCHECK := $(shell if command -v cppcheck >/dev/null 2>&1; then echo cppcheck; CLANG_TIDY_EXTRA_ARGS := $(shell if [ "$$(uname)" = "Darwin" ]; then echo "--extra-arg=--sysroot=$$(xcrun --show-sdk-path)"; fi) SRC_FILES := src/*.c include/*.h -TEST_FILES := tests/unit/*.c +TEST_FILES := $(wildcard tests/unit/*.c tests/api/*.c) CMD_FILES := $(wildcard cmd/*/*.c cmd/*/*.h) ALL_FILES := $(SRC_FILES) $(TEST_FILES) $(CMD_FILES) LINT_FILES := $(shell find src tests -type f -name '*.c') diff --git a/include/tl_app.h b/include/tl_app.h index 6c39607..d973b49 100644 --- a/include/tl_app.h +++ b/include/tl_app.h @@ -11,6 +11,6 @@ * * @return void */ -void tl_init_app(int argc, char *argv[]); +void tl_app_init(int argc, char *argv[]); #endif // TL_APP_H diff --git a/include/tl_config.h b/include/tl_config.h index 4eaaf8f..28ecd6d 100644 --- a/include/tl_config.h +++ b/include/tl_config.h @@ -12,9 +12,9 @@ * @note Available for certain ARM architectures. */ #if defined(__ARM_NEON) || defined(__ARM_NEON__) -#define TL_NEON_AVAILABLE 1 +#define TL_HAS_NEON 1 #else -#define TL_NEON_AVAILABLE 0 +#define TL_HAS_NEON 0 #endif /** @@ -23,9 +23,9 @@ * @note Available for all ARM architectures. */ #ifdef __ARM_ARCH -#define TL_CMSIS_DSP_AVAILABLE 1 +#define TL_HAS_CMSIS_DSP 1 #else -#define TL_CMSIS_DSP_AVAILABLE 0 +#define TL_HAS_CMSIS_DSP 0 #endif /** @@ -33,29 +33,29 @@ * * @return The debug level. */ -int tl_get_debug_level(); +int tl_config_get_debug_level(); /** * @brief Sets the debug level. * * @param level The debug level. * - * @return True or false. + * @return void */ -bool tl_set_debug_level(int level); +void tl_config_set_debug_level(int level); /** * @brief Returns whether ARM NEON is available. * * @return True or false. */ -bool tl_neon_available(); +bool tl_config_has_neon(); /** * @brief Returns whether ARM CMSIS-DSP is available. * * @return True or false. */ -bool tl_cmsis_dsp_available(); +bool tl_config_has_cmsis_dsp(); #endif // TL_CONFIG_H diff --git a/include/tl_debug.h b/include/tl_debug.h index 62f707f..f1d602e 100644 --- a/include/tl_debug.h +++ b/include/tl_debug.h @@ -16,10 +16,10 @@ * * @return void */ -#define TL_DEBUG_PRINT(level, fmt, ...) \ - do { \ - if (tl_get_debug_level() >= level) \ - fprintf(stderr, fmt, ##__VA_ARGS__); \ +#define TL_DEBUG_PRINT(level, fmt, ...) \ + do { \ + if (tl_config_get_debug_level() >= level) \ + fprintf(stderr, fmt, ##__VA_ARGS__); \ } while (0) #endif // TL_DEBUG_H diff --git a/include/tl_error.h b/include/tl_error.h index 9582644..04dc03a 100644 --- a/include/tl_error.h +++ b/include/tl_error.h @@ -30,7 +30,7 @@ typedef enum { TL_ERROR_INVALID_SIZE = 36, // invalid size TL_ERROR_INVALID_TYPE = 37, // invalid type TL_ERROR_INVALID_VALUE = 38, // invalid value -} TLErrorCode; +} TlErrorCode; /** * @brief Represents an error. @@ -40,21 +40,20 @@ typedef enum { * @param message The error message. */ typedef struct { - TLErrorCode code; + TlErrorCode code; size_t message_size; const char *message; -} TLError; +} TlError; /** * @brief Sets the error with the given code and message. * * @param error The error to set. * @param code The error code. - * @param message The error message. - * @param ... The arguments for the formatted message. + * @param ... The error message followed by the formatted message arguments. * - * @return void + * @return TL_ERROR_NONE on success, or an error code on failure. */ -void tl_error_set(TLError *error, TLErrorCode code, const char *message, ...); +int tl_error_set_message(TlError *error, TlErrorCode code, ...); #endif // TL_ERROR_H diff --git a/include/tl_flag.h b/include/tl_flag.h index 4a50f37..82a13e5 100644 --- a/include/tl_flag.h +++ b/include/tl_flag.h @@ -79,7 +79,7 @@ typedef enum { * * @return The argv index, or TL_ARG_NOT_FOUND when not found. */ -size_t tl_arg_index(int argc, char *argv[], const char *name); +size_t tl_flag_get_arg_index(int argc, char *argv[], const char *name); /** * @brief Returns the first argv index matching the given name after an index. @@ -93,13 +93,13 @@ size_t tl_arg_index(int argc, char *argv[], const char *name); * * @return The argv index, or TL_ARG_NOT_FOUND when not found. */ -size_t tl_arg_index_after(int argc, char *argv[], const char *name, size_t index); +size_t tl_flag_get_arg_index_after(int argc, char *argv[], const char *name, size_t index); /** * @brief Parses the given command line arguments with options. * * Default parsing is used when options is NULL or both option lists are NULL. - * With default parsing this behaves like tl_parse_args. Strict mode is enabled + * With default parsing this behaves like tl_flag_parse_args. Strict mode is enabled * when either option list is non-NULL. * * @param argc The number of command line arguments. @@ -108,7 +108,8 @@ size_t tl_arg_index_after(int argc, char *argv[], const char *name, size_t index * * @return TL_PARSE_OK on success, or a negative parse error. */ -TlParseResult tl_parse_args_ex(int argc, char *argv[], const TlParseOptions *options); +TlParseResult tl_flag_parse_args_with_options(int argc, char *argv[], + const TlParseOptions *options); /** * @brief Parses an explicit argv range. @@ -125,8 +126,8 @@ TlParseResult tl_parse_args_ex(int argc, char *argv[], const TlParseOptions *opt * * @return TL_PARSE_OK on success, or a negative parse error. */ -TlParseResult tl_parse_args_range(int argc, char *argv[], size_t start_index, size_t end_index, - const TlParseOptions *options); +TlParseResult tl_flag_parse_args_range(int argc, char *argv[], size_t start_index, size_t end_index, + const TlParseOptions *options); /** * @brief Parses the given command line arguments. @@ -143,7 +144,7 @@ TlParseResult tl_parse_args_range(int argc, char *argv[], size_t start_index, si * * @return TL_PARSE_OK on success, or a negative parse error. */ -TlParseResult tl_parse_args(int argc, char *argv[]); +TlParseResult tl_flag_parse_args(int argc, char *argv[]); /** * @brief Parses a raw command line string. @@ -156,17 +157,17 @@ TlParseResult tl_parse_args(int argc, char *argv[]); * * @return TL_PARSE_OK on success, or a negative parse error. */ -TlParseResult tl_parse_line(const char *line); +TlParseResult tl_flag_parse_line(const char *line); /** * @brief Releases memory held by the argument parser. * * Safe to call when nothing has been parsed. Called implicitly by - * tl_parse_args and tl_parse_line. + * tl_flag_parse_args and tl_flag_parse_line. * * @return void */ -void tl_free_args(void); +void tl_flag_free_args(void); /** * @brief Looks up a specific flag. @@ -175,19 +176,19 @@ void tl_free_args(void); * * @return true if the flag is found, false otherwise. */ -bool tl_lookup_flag(const char *flag); +bool tl_flag_has_flag(const char *flag); /** * @brief Returns the value of a specific flag. * * Returns the value of the first occurrence of flag. For repeated flags - * use tl_count_flag and tl_get_flag_at. + * use tl_flag_count_flag and tl_flag_get_value_at. * * @param flag The flag to get. * * @return The value of the flag, or NULL if not found or no value. */ -const char *tl_get_flag(const char *flag); +const char *tl_flag_get_value(const char *flag); /** * @brief Returns the number of times a flag was given. @@ -196,7 +197,7 @@ const char *tl_get_flag(const char *flag); * * @return The occurrence count (0 if not given). */ -size_t tl_count_flag(const char *flag); +size_t tl_flag_count_flag(const char *flag); /** * @brief Returns the value of a repeated flag at a given index. @@ -208,7 +209,7 @@ size_t tl_count_flag(const char *flag); * * @return The value, or NULL if out of range or no value at that index. */ -const char *tl_get_flag_at(const char *flag, size_t index); +const char *tl_flag_get_value_at(const char *flag, size_t index); /** * @brief Looks up a specific positional argument by value. @@ -217,7 +218,7 @@ const char *tl_get_flag_at(const char *flag, size_t index); * * @return true if the positional is found, false otherwise. */ -bool tl_lookup_positional(const char *value); +bool tl_flag_has_positional(const char *value); /** * @brief Returns the number of positional arguments. @@ -227,7 +228,7 @@ bool tl_lookup_positional(const char *value); * * @return The positional argument count. */ -size_t tl_count_positional(void); +size_t tl_flag_count_positional(void); /** * @brief Returns the positional argument at the given index. @@ -236,6 +237,6 @@ size_t tl_count_positional(void); * * @return The positional value, or NULL if out of range. */ -const char *tl_get_positional(size_t index); +const char *tl_flag_get_positional(size_t index); #endif // TL_FLAG_H diff --git a/include/tl_test.h b/include/tl_test.h index 93705f3..e569e97 100644 --- a/include/tl_test.h +++ b/include/tl_test.h @@ -13,6 +13,6 @@ * * @return The difference between the two timespec structures in nanoseconds. */ -long long tl_timespec_diff_ns(const struct timespec *start, const struct timespec *end); +long long tl_test_get_timespec_diff_ns(const struct timespec *start, const struct timespec *end); #endif // TL_TEST_H diff --git a/src/tl_app.c b/src/tl_app.c index df57e5a..5e94a9a 100644 --- a/src/tl_app.c +++ b/src/tl_app.c @@ -5,9 +5,9 @@ #include "tl_flag.h" #include -void tl_init_app(int argc, char *argv[]) { - tl_parse_args(argc, argv); - if (tl_get_flag("--debug-level")) { - tl_set_debug_level((int)strtol(tl_get_flag("--debug-level"), NULL, 10)); +void tl_app_init(int argc, char *argv[]) { + tl_flag_parse_args(argc, argv); + if (tl_flag_get_value("--debug-level")) { + tl_config_set_debug_level((int)strtol(tl_flag_get_value("--debug-level"), NULL, 10)); } } diff --git a/src/tl_config.c b/src/tl_config.c index 016bbff..58c9092 100644 --- a/src/tl_config.c +++ b/src/tl_config.c @@ -8,25 +8,24 @@ */ static int debug_level = 0; -int tl_get_debug_level() { +int tl_config_get_debug_level() { return debug_level; } -bool tl_set_debug_level(int level) { +void tl_config_set_debug_level(int level) { debug_level = level; - return true; } -bool tl_neon_available() { -#if TL_NEON_AVAILABLE +bool tl_config_has_neon() { +#if TL_HAS_NEON return true; #else return false; #endif } -bool tl_cmsis_dsp_available() { -#if TL_CMSIS_DSP_AVAILABLE +bool tl_config_has_cmsis_dsp() { +#if TL_HAS_CMSIS_DSP return true; #else return false; diff --git a/src/tl_error.c b/src/tl_error.c index 30a3f1a..a99be5e 100644 --- a/src/tl_error.c +++ b/src/tl_error.c @@ -6,14 +6,14 @@ #include #include -void tl_error_set(TLError *error, TLErrorCode code, const char *message, ...) { - // Ignore if error is NULL +int tl_error_set_message(TlError *error, TlErrorCode code, ...) { if (!error) { - return; + return TL_ERROR_INVALID_ARGUMENT; } - // Set error code and message + // Set error code error->code = code; + // Clear previous error message if (error->message) { free((void *)error->message); @@ -22,24 +22,30 @@ void tl_error_set(TLError *error, TLErrorCode code, const char *message, ...) { } // Set message if provided + va_list args; + va_start(args, code); + const char *message = va_arg(args, const char *); if (message) { - va_list args; - va_start(args, message); - int size = vsnprintf(NULL, 0, message, args); - va_end(args); + va_list format_args; + va_copy(format_args, args); + int size = vsnprintf(NULL, 0, message, format_args); + va_end(format_args); if (size < 0) { - return; // ignore if vsnprintf fails + va_end(args); + return TL_ERROR_INTERNAL; } error->message = malloc(size + 1); // include null terminator by adding 1 if (!error->message) { - return; // ignore if malloc fails + va_end(args); + return TL_ERROR_MEMORY_ALLOCATION; } error->message_size = size + 1; - va_start(args, message); vsnprintf((char *)error->message, error->message_size, message, args); - va_end(args); } + va_end(args); + + return TL_ERROR_NONE; } diff --git a/src/tl_flag.c b/src/tl_flag.c index a75278f..091b29e 100644 --- a/src/tl_flag.c +++ b/src/tl_flag.c @@ -325,7 +325,7 @@ static TlParseResult tokenize_line(const char *line, size_t *token_count) { return TL_PARSE_OK; } -size_t tl_arg_index(int argc, char *argv[], const char *name) { +size_t tl_flag_get_arg_index(int argc, char *argv[], const char *name) { if (argc <= 0 || !argv || !name) { return TL_ARG_NOT_FOUND; } @@ -337,7 +337,7 @@ size_t tl_arg_index(int argc, char *argv[], const char *name) { return TL_ARG_NOT_FOUND; } -size_t tl_arg_index_after(int argc, char *argv[], const char *name, size_t index) { +size_t tl_flag_get_arg_index_after(int argc, char *argv[], const char *name, size_t index) { if (index == TL_ARG_NOT_FOUND || argc <= 0 || !argv || !name) { return TL_ARG_NOT_FOUND; } @@ -353,21 +353,22 @@ size_t tl_arg_index_after(int argc, char *argv[], const char *name, size_t index return TL_ARG_NOT_FOUND; } -TlParseResult tl_parse_args_ex(int argc, char *argv[], const TlParseOptions *options) { - tl_free_args(); +TlParseResult tl_flag_parse_args_with_options(int argc, char *argv[], + const TlParseOptions *options) { + tl_flag_free_args(); if (argc <= 1 || !argv) { return TL_PARSE_OK; } TlParseResult result = parse_token_range(argv, 1, (size_t)argc, options); if (result != TL_PARSE_OK) { - tl_free_args(); + tl_flag_free_args(); } return result; } -TlParseResult tl_parse_args_range(int argc, char *argv[], size_t start_index, size_t end_index, - const TlParseOptions *options) { - tl_free_args(); +TlParseResult tl_flag_parse_args_range(int argc, char *argv[], size_t start_index, size_t end_index, + const TlParseOptions *options) { + tl_flag_free_args(); if (argc < 0 || start_index == TL_ARG_NOT_FOUND || end_index == TL_ARG_NOT_FOUND || start_index > end_index || start_index > (size_t)argc || end_index > (size_t)argc) { return TL_PARSE_ERROR_INVALID_RANGE; @@ -377,24 +378,24 @@ TlParseResult tl_parse_args_range(int argc, char *argv[], size_t start_index, si } TlParseResult result = parse_token_range(argv, start_index, end_index, options); if (result != TL_PARSE_OK) { - tl_free_args(); + tl_flag_free_args(); } return result; } -TlParseResult tl_parse_args(int argc, char *argv[]) { - return tl_parse_args_ex(argc, argv, NULL); +TlParseResult tl_flag_parse_args(int argc, char *argv[]) { + return tl_flag_parse_args_with_options(argc, argv, NULL); } -TlParseResult tl_parse_line(const char *line) { - tl_free_args(); +TlParseResult tl_flag_parse_line(const char *line) { + tl_flag_free_args(); if (!line) { return TL_PARSE_ERROR_INVALID_INPUT; } size_t n = 0; TlParseResult result = tokenize_line(line, &n); if (result != TL_PARSE_OK) { - tl_free_args(); + tl_flag_free_args(); return result; } if (n <= 1) { @@ -402,12 +403,12 @@ TlParseResult tl_parse_line(const char *line) { } result = parse_token_range(line_tokens, 1, n, NULL); if (result != TL_PARSE_OK) { - tl_free_args(); + tl_flag_free_args(); } return result; } -void tl_free_args(void) { +void tl_flag_free_args(void) { if (flags) { free(flags); flags = NULL; @@ -428,7 +429,7 @@ void tl_free_args(void) { } } -bool tl_lookup_flag(const char *flag) { +bool tl_flag_has_flag(const char *flag) { if (!flag) { return false; } @@ -441,11 +442,11 @@ bool tl_lookup_flag(const char *flag) { return false; } -const char *tl_get_flag(const char *flag) { - return tl_get_flag_at(flag, 0); +const char *tl_flag_get_value(const char *flag) { + return tl_flag_get_value_at(flag, 0); } -size_t tl_count_flag(const char *flag) { +size_t tl_flag_count_flag(const char *flag) { if (!flag) { return 0; } @@ -459,7 +460,7 @@ size_t tl_count_flag(const char *flag) { return n; } -const char *tl_get_flag_at(const char *flag, size_t index) { +const char *tl_flag_get_value_at(const char *flag, size_t index) { if (!flag) { return NULL; } @@ -476,7 +477,7 @@ const char *tl_get_flag_at(const char *flag, size_t index) { return NULL; } -bool tl_lookup_positional(const char *value) { +bool tl_flag_has_positional(const char *value) { if (!value) { return false; } @@ -488,11 +489,11 @@ bool tl_lookup_positional(const char *value) { return false; } -size_t tl_count_positional(void) { +size_t tl_flag_count_positional(void) { return positional_count; } -const char *tl_get_positional(size_t index) { +const char *tl_flag_get_positional(size_t index) { if (index >= positional_count) { return NULL; } diff --git a/src/tl_test.c b/src/tl_test.c index dedad52..60abc28 100644 --- a/src/tl_test.c +++ b/src/tl_test.c @@ -5,6 +5,6 @@ // TODO: Add tests -long long tl_timespec_diff_ns(const struct timespec *start, const struct timespec *end) { +long long tl_test_get_timespec_diff_ns(const struct timespec *start, const struct timespec *end) { return ((end->tv_sec - start->tv_sec) * 1000000000LL) + (end->tv_nsec - start->tv_nsec); } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 805f892..09c9958 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,20 +1,35 @@ set(TEST_BIN_DIR "${PROJECT_BINARY_DIR}/tests/bin") set(UNIT_TEST_TARGETS - app_test - config_test - debug_test - error_test - flag_test - test_test +) + +set(API_TEST_TARGETS + test_api_app + test_api_config + test_api_debug + test_api_error + test_api_flag + test_api_test ) foreach(test_target IN LISTS UNIT_TEST_TARGETS) - string(REGEX REPLACE "_test$" "" test_name "${test_target}") - set(test_binary "tl_${test_name}") - add_executable(${test_binary} unit/${test_target}.c) + set(test_binary "${test_target}") + set(test_sources unit/${test_target}.c) + add_executable(${test_binary} ${test_sources}) target_link_libraries(${test_binary} PRIVATE tinyclib unity) target_include_directories(${test_binary} PRIVATE ${PROJECT_SOURCE_DIR}/src) + tl_configure_c_target(${test_binary}) + set_target_properties(${test_binary} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${TEST_BIN_DIR}) + add_test(NAME ${test_binary} COMMAND ${test_binary}) +endforeach() + +foreach(test_target IN LISTS API_TEST_TARGETS) + set(test_binary "${test_target}") + set(test_sources api/${test_target}.c) + add_executable(${test_binary} ${test_sources}) + target_link_libraries(${test_binary} PRIVATE tinyclib unity) + target_include_directories(${test_binary} PRIVATE ${PROJECT_SOURCE_DIR}/include) + tl_configure_c_target(${test_binary}) set_target_properties(${test_binary} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${TEST_BIN_DIR}) add_test(NAME ${test_binary} COMMAND ${test_binary}) endforeach() diff --git a/tests/api/test_api_app.c b/tests/api/test_api_app.c new file mode 100644 index 0000000..037d217 --- /dev/null +++ b/tests/api/test_api_app.c @@ -0,0 +1,34 @@ +#include "tl_app.h" +#include "tl_flag.h" +#include "unity.h" + +void setUp(void) { + // Setup code if needed +} + +void tearDown(void) { + tl_flag_free_args(); +} + +static void test_tl_app_init_equals_debug_level(void) { + char *argv[] = {"program", "--debug-level=2"}; + tl_app_init(2, argv); + TEST_ASSERT_TRUE(tl_flag_has_flag("--debug-level")); + TEST_ASSERT_EQUAL_STRING("2", tl_flag_get_value("--debug-level")); +} + +static void test_tl_app_init_space_debug_level(void) { + char *argv[] = {"program", "--debug-level", "3"}; + tl_app_init(3, argv); + TEST_ASSERT_TRUE(tl_flag_has_flag("--debug-level")); + TEST_ASSERT_EQUAL_STRING("3", tl_flag_get_value("--debug-level")); +} + +int main(void) { + UNITY_BEGIN(); + + RUN_TEST(test_tl_app_init_equals_debug_level); + RUN_TEST(test_tl_app_init_space_debug_level); + + return UNITY_END(); +} diff --git a/tests/api/test_api_config.c b/tests/api/test_api_config.c new file mode 100644 index 0000000..7671285 --- /dev/null +++ b/tests/api/test_api_config.c @@ -0,0 +1,47 @@ +#include "tl_config.h" +#include "unity.h" + +void setUp(void) { + // Setup code if needed +} + +void tearDown(void) { + // Teardown code if needed +} + +static void test_tl_config_get_debug_level_returns_level(void) { + tl_config_set_debug_level(3); + TEST_ASSERT_EQUAL(3, tl_config_get_debug_level()); +} + +static void test_tl_config_set_debug_level_sets_level(void) { + tl_config_set_debug_level(5); + TEST_ASSERT_EQUAL(5, tl_config_get_debug_level()); +} + +static void test_tl_config_has_neon_matches_macro(void) { +#if TL_HAS_NEON + TEST_ASSERT_TRUE(tl_config_has_neon()); +#else + TEST_ASSERT_FALSE(tl_config_has_neon()); +#endif +} + +static void test_tl_config_has_cmsis_dsp_matches_macro(void) { +#if TL_HAS_CMSIS_DSP + TEST_ASSERT_TRUE(tl_config_has_cmsis_dsp()); +#else + TEST_ASSERT_FALSE(tl_config_has_cmsis_dsp()); +#endif +} + +int main(void) { + UNITY_BEGIN(); + + RUN_TEST(test_tl_config_get_debug_level_returns_level); + RUN_TEST(test_tl_config_set_debug_level_sets_level); + RUN_TEST(test_tl_config_has_neon_matches_macro); + RUN_TEST(test_tl_config_has_cmsis_dsp_matches_macro); + + return UNITY_END(); +} diff --git a/tests/unit/debug_test.c b/tests/api/test_api_debug.c similarity index 71% rename from tests/unit/debug_test.c rename to tests/api/test_api_debug.c index c78132f..4440b22 100644 --- a/tests/unit/debug_test.c +++ b/tests/api/test_api_debug.c @@ -9,13 +9,13 @@ void tearDown(void) { // Teardown code if needed } -static void test_tl_debug_functionality(void) { +static void test_tl_debug_print_placeholder_asserts_true(void) { // Example test for tl_debug functionality TEST_ASSERT_TRUE(1); // Replace with actual tests } int main(void) { UNITY_BEGIN(); - RUN_TEST(test_tl_debug_functionality); + RUN_TEST(test_tl_debug_print_placeholder_asserts_true); return UNITY_END(); } diff --git a/tests/api/test_api_error.c b/tests/api/test_api_error.c new file mode 100644 index 0000000..34c1fbb --- /dev/null +++ b/tests/api/test_api_error.c @@ -0,0 +1,51 @@ +#include "tl_error.h" +#include "unity.h" +#include +#include + +void setUp(void) { + // Setup code if needed +} + +void tearDown(void) { + // Teardown code if needed +} + +static void test_tl_error_set_message_fixed_message_sets_error(void) { + TlError error = {0}; + int result = tl_error_set_message(&error, TL_ERROR_INTERNAL, "fixed error message"); + + TEST_ASSERT_EQUAL_INT(TL_ERROR_NONE, result); + TEST_ASSERT_EQUAL(TL_ERROR_INTERNAL, error.code); + TEST_ASSERT_NOT_NULL(error.message); + TEST_ASSERT_EQUAL_STRING("fixed error message", error.message); + + free((void *)error.message); +} + +static void test_tl_error_set_message_formatted_message_sets_error(void) { + TlError error = {0}; + int result = tl_error_set_message(&error, TL_ERROR_NOT_FOUND, "formatted error: %d", 42); + + TEST_ASSERT_EQUAL_INT(TL_ERROR_NONE, result); + TEST_ASSERT_EQUAL(TL_ERROR_NOT_FOUND, error.code); + TEST_ASSERT_NOT_NULL(error.message); + TEST_ASSERT_EQUAL_STRING("formatted error: 42", error.message); + + free((void *)error.message); +} + +static void test_tl_error_set_message_null_error_returns_invalid_argument(void) { + TEST_ASSERT_EQUAL_INT(TL_ERROR_INVALID_ARGUMENT, + tl_error_set_message(NULL, TL_ERROR_NOT_READY, "this should not crash")); +} + +int main(void) { + UNITY_BEGIN(); + + RUN_TEST(test_tl_error_set_message_fixed_message_sets_error); + RUN_TEST(test_tl_error_set_message_formatted_message_sets_error); + RUN_TEST(test_tl_error_set_message_null_error_returns_invalid_argument); + + return UNITY_END(); +} diff --git a/tests/api/test_api_flag.c b/tests/api/test_api_flag.c new file mode 100644 index 0000000..344d434 --- /dev/null +++ b/tests/api/test_api_flag.c @@ -0,0 +1,810 @@ +#include "tl_flag.h" +#include "unity.h" + +void setUp(void) { + // Setup code if needed +} + +void tearDown(void) { + tl_flag_free_args(); +} + +static void test_tl_flag_parse_args_single_flag_sets_flag(void) { + char *argv[] = {"program", "--test-flag"}; + TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_flag_parse_args(2, argv)); + TEST_ASSERT_TRUE(tl_flag_has_flag("--test-flag")); +} + +static void test_tl_flag_has_flag_existing_flag_returns_true(void) { + char *argv[] = {"program", "--test-flag"}; + tl_flag_parse_args(2, argv); + TEST_ASSERT_TRUE(tl_flag_has_flag("--test-flag")); + TEST_ASSERT_FALSE(tl_flag_has_flag("--nonexistent-flag")); +} + +static void test_tl_flag_get_value_equals_value_returns_value(void) { + char *argv[] = {"program", "--key=value"}; + tl_flag_parse_args(2, argv); + TEST_ASSERT_EQUAL_STRING("value", tl_flag_get_value("--key")); + TEST_ASSERT_NULL(tl_flag_get_value("--nonexistent-key")); +} + +static void test_tl_flag_get_value_space(void) { + char *argv[] = {"program", "--key", "value"}; + tl_flag_parse_args(3, argv); + TEST_ASSERT_EQUAL_STRING("value", tl_flag_get_value("--key")); +} + +static void test_tl_flag_get_value_partial_name_returns_null(void) { + char *argv[] = {"program", "--foobar=1"}; + tl_flag_parse_args(2, argv); + TEST_ASSERT_FALSE(tl_flag_has_flag("--foo")); + TEST_ASSERT_NULL(tl_flag_get_value("--foo")); + TEST_ASSERT_EQUAL_STRING("1", tl_flag_get_value("--foobar")); +} + +static void test_tl_flag_parse_args_repeated_flag_equals(void) { + char *argv[] = {"program", "--foo=x", "--foo=y", "--foo=z"}; + tl_flag_parse_args(4, argv); + TEST_ASSERT_EQUAL_UINT(3, tl_flag_count_flag("--foo")); + TEST_ASSERT_EQUAL_STRING("x", tl_flag_get_value_at("--foo", 0)); + TEST_ASSERT_EQUAL_STRING("y", tl_flag_get_value_at("--foo", 1)); + TEST_ASSERT_EQUAL_STRING("z", tl_flag_get_value_at("--foo", 2)); + TEST_ASSERT_NULL(tl_flag_get_value_at("--foo", 3)); + TEST_ASSERT_EQUAL_STRING("x", tl_flag_get_value("--foo")); +} + +static void test_tl_flag_parse_args_repeated_flag_mixed(void) { + char *argv[] = {"program", "--foo=x", "--foo", "y", "--foo=z"}; + tl_flag_parse_args(5, argv); + TEST_ASSERT_EQUAL_UINT(3, tl_flag_count_flag("--foo")); + TEST_ASSERT_EQUAL_STRING("x", tl_flag_get_value_at("--foo", 0)); + TEST_ASSERT_EQUAL_STRING("y", tl_flag_get_value_at("--foo", 1)); + TEST_ASSERT_EQUAL_STRING("z", tl_flag_get_value_at("--foo", 2)); +} + +static void test_tl_flag_parse_args_repeated_boolean_flag(void) { + char *argv[] = {"program", "--verbose", "--verbose", "--verbose"}; + tl_flag_parse_args(4, argv); + TEST_ASSERT_EQUAL_UINT(3, tl_flag_count_flag("--verbose")); + TEST_ASSERT_NULL(tl_flag_get_value_at("--verbose", 0)); + TEST_ASSERT_NULL(tl_flag_get_value_at("--verbose", 1)); + TEST_ASSERT_NULL(tl_flag_get_value_at("--verbose", 2)); +} + +static void test_tl_flag_parse_args_adjacent_space_flags(void) { + char *argv[] = {"program", "--foo", "x", "--bar", "y"}; + tl_flag_parse_args(5, argv); + TEST_ASSERT_EQUAL_STRING("x", tl_flag_get_value("--foo")); + TEST_ASSERT_EQUAL_STRING("y", tl_flag_get_value("--bar")); +} + +static void test_tl_flag_parse_args_space_flag_trailing_boolean(void) { + char *argv[] = {"program", "--foo", "x", "--bar"}; + tl_flag_parse_args(4, argv); + TEST_ASSERT_EQUAL_STRING("x", tl_flag_get_value("--foo")); + TEST_ASSERT_TRUE(tl_flag_has_flag("--bar")); + TEST_ASSERT_NULL(tl_flag_get_value("--bar")); +} + +static void test_tl_flag_parse_args_positional_terminator(void) { + char *argv[] = {"program", "command", "--foo", "--", "--baz", "--qux"}; + tl_flag_parse_args(6, argv); + TEST_ASSERT_TRUE(tl_flag_has_flag("--foo")); + TEST_ASSERT_NULL(tl_flag_get_value("--foo")); + TEST_ASSERT_FALSE(tl_flag_has_flag("--baz")); + TEST_ASSERT_FALSE(tl_flag_has_flag("--qux")); + TEST_ASSERT_EQUAL_UINT(3, tl_flag_count_positional()); + TEST_ASSERT_EQUAL_STRING("command", tl_flag_get_positional(0)); + TEST_ASSERT_EQUAL_STRING("--baz", tl_flag_get_positional(1)); + TEST_ASSERT_EQUAL_STRING("--qux", tl_flag_get_positional(2)); + TEST_ASSERT_NULL(tl_flag_get_positional(3)); +} + +static void test_tl_flag_parse_args_positional_interleaved(void) { + char *argv[] = {"program", "foo", "--flag", "val", "bar"}; + tl_flag_parse_args(5, argv); + TEST_ASSERT_EQUAL_STRING("val", tl_flag_get_value("--flag")); + TEST_ASSERT_EQUAL_UINT(2, tl_flag_count_positional()); + TEST_ASSERT_EQUAL_STRING("foo", tl_flag_get_positional(0)); + TEST_ASSERT_EQUAL_STRING("bar", tl_flag_get_positional(1)); +} + +static void test_tl_flag_parse_args_quoted_value_from_argv(void) { + char *argv[] = {"program", "--foo", "bar baz qux"}; + tl_flag_parse_args(3, argv); + TEST_ASSERT_EQUAL_STRING("bar baz qux", tl_flag_get_value("--foo")); +} + +static void test_tl_flag_parse_line_quoted(void) { + TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_flag_parse_line("program --foo \"bar baz qux\"")); + TEST_ASSERT_EQUAL_STRING("bar baz qux", tl_flag_get_value("--foo")); +} + +static void test_tl_flag_parse_line_escape(void) { + TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_flag_parse_line("program --foo \"a\\\"b\"")); + TEST_ASSERT_EQUAL_STRING("a\"b", tl_flag_get_value("--foo")); +} + +static void test_tl_flag_parse_line_full(void) { + TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, + tl_flag_parse_line("prog cmd --foo=1 --foo 2 --bar \"x y\" -- --baz")); + TEST_ASSERT_EQUAL_UINT(2, tl_flag_count_flag("--foo")); + TEST_ASSERT_EQUAL_STRING("1", tl_flag_get_value_at("--foo", 0)); + TEST_ASSERT_EQUAL_STRING("2", tl_flag_get_value_at("--foo", 1)); + TEST_ASSERT_EQUAL_STRING("x y", tl_flag_get_value("--bar")); + TEST_ASSERT_EQUAL_UINT(2, tl_flag_count_positional()); + TEST_ASSERT_EQUAL_STRING("cmd", tl_flag_get_positional(0)); + TEST_ASSERT_EQUAL_STRING("--baz", tl_flag_get_positional(1)); +} + +static void test_tl_flag_parse_line_unterminated(void) { + TEST_ASSERT_EQUAL_INT(TL_PARSE_ERROR_UNTERMINATED_QUOTE, + tl_flag_parse_line("program --foo \"unterminated")); +} + +static void test_tl_flag_parse_line_null(void) { + TEST_ASSERT_EQUAL_INT(TL_PARSE_ERROR_INVALID_INPUT, tl_flag_parse_line(NULL)); +} + +static void test_tl_flag_parse_args_short_flag(void) { + char *argv[] = {"program", "-h"}; + tl_flag_parse_args(2, argv); + TEST_ASSERT_TRUE(tl_flag_has_flag("-h")); + TEST_ASSERT_NULL(tl_flag_get_value("-h")); + TEST_ASSERT_EQUAL_UINT(0, tl_flag_count_positional()); +} + +static void test_tl_flag_parse_args_short_flag_value(void) { + char *argv[] = {"program", "-o", "out.txt", "-v"}; + tl_flag_parse_args(4, argv); + TEST_ASSERT_EQUAL_STRING("out.txt", tl_flag_get_value("-o")); + TEST_ASSERT_TRUE(tl_flag_has_flag("-v")); + TEST_ASSERT_NULL(tl_flag_get_value("-v")); +} + +static void test_tl_flag_parse_args_short_flag_equals(void) { + char *argv[] = {"program", "-o=out.txt"}; + tl_flag_parse_args(2, argv); + TEST_ASSERT_EQUAL_STRING("out.txt", tl_flag_get_value("-o")); +} + +static void test_tl_flag_parse_args_bare_dash_is_positional(void) { + char *argv[] = {"program", "-"}; + tl_flag_parse_args(2, argv); + TEST_ASSERT_FALSE(tl_flag_has_flag("-")); + TEST_ASSERT_EQUAL_UINT(1, tl_flag_count_positional()); + TEST_ASSERT_EQUAL_STRING("-", tl_flag_get_positional(0)); +} + +static void test_tl_flag_parse_args_short_flag_exact_match(void) { + char *argv[] = {"program", "-help"}; + tl_flag_parse_args(2, argv); + TEST_ASSERT_FALSE(tl_flag_has_flag("-h")); + TEST_ASSERT_NULL(tl_flag_get_value("-h")); + TEST_ASSERT_TRUE(tl_flag_has_flag("-help")); +} + +static void test_tl_flag_parse_args_short_repeated_boolean(void) { + char *argv[] = {"program", "-v", "-v", "-v"}; + tl_flag_parse_args(4, argv); + TEST_ASSERT_EQUAL_UINT(3, tl_flag_count_flag("-v")); + TEST_ASSERT_NULL(tl_flag_get_value_at("-v", 0)); + TEST_ASSERT_NULL(tl_flag_get_value_at("-v", 1)); + TEST_ASSERT_NULL(tl_flag_get_value_at("-v", 2)); +} + +static void test_tl_flag_parse_args_short_repeated_mixed(void) { + char *argv[] = {"program", "-o=a", "-o", "b", "-o=c"}; + tl_flag_parse_args(5, argv); + TEST_ASSERT_EQUAL_UINT(3, tl_flag_count_flag("-o")); + TEST_ASSERT_EQUAL_STRING("a", tl_flag_get_value_at("-o", 0)); + TEST_ASSERT_EQUAL_STRING("b", tl_flag_get_value_at("-o", 1)); + TEST_ASSERT_EQUAL_STRING("c", tl_flag_get_value_at("-o", 2)); +} + +static void test_tl_flag_parse_args_short_adjacent(void) { + char *argv[] = {"program", "-a", "x", "-b", "y"}; + tl_flag_parse_args(5, argv); + TEST_ASSERT_EQUAL_STRING("x", tl_flag_get_value("-a")); + TEST_ASSERT_EQUAL_STRING("y", tl_flag_get_value("-b")); +} + +static void test_tl_flag_parse_args_short_trailing_boolean(void) { + char *argv[] = {"program", "-o", "-v"}; + tl_flag_parse_args(3, argv); + TEST_ASSERT_TRUE(tl_flag_has_flag("-o")); + TEST_ASSERT_NULL(tl_flag_get_value("-o")); + TEST_ASSERT_TRUE(tl_flag_has_flag("-v")); + TEST_ASSERT_NULL(tl_flag_get_value("-v")); +} + +static void test_tl_flag_parse_args_short_value_is_bare_dash(void) { + char *argv[] = {"program", "-o", "-"}; + tl_flag_parse_args(3, argv); + TEST_ASSERT_EQUAL_STRING("-", tl_flag_get_value("-o")); + TEST_ASSERT_EQUAL_UINT(0, tl_flag_count_positional()); +} + +static void test_tl_flag_parse_args_short_long_mixed(void) { + char *argv[] = {"program", "-v", "--name=foo", "-o", "out", "--flag"}; + tl_flag_parse_args(6, argv); + TEST_ASSERT_TRUE(tl_flag_has_flag("-v")); + TEST_ASSERT_EQUAL_STRING("foo", tl_flag_get_value("--name")); + TEST_ASSERT_EQUAL_STRING("out", tl_flag_get_value("-o")); + TEST_ASSERT_TRUE(tl_flag_has_flag("--flag")); + TEST_ASSERT_NULL(tl_flag_get_value("--flag")); +} + +static void test_tl_flag_parse_args_short_followed_by_long(void) { + char *argv[] = {"program", "-o", "--other"}; + tl_flag_parse_args(3, argv); + TEST_ASSERT_TRUE(tl_flag_has_flag("-o")); + TEST_ASSERT_NULL(tl_flag_get_value("-o")); + TEST_ASSERT_TRUE(tl_flag_has_flag("--other")); +} + +static void test_tl_flag_parse_args_positional_dashdash_trailing_empty(void) { + char *argv[] = {"program", "--foo", "--"}; + tl_flag_parse_args(3, argv); + TEST_ASSERT_TRUE(tl_flag_has_flag("--foo")); + TEST_ASSERT_NULL(tl_flag_get_value("--foo")); + TEST_ASSERT_EQUAL_UINT(0, tl_flag_count_positional()); +} + +static void test_tl_flag_parse_args_positional_second_dashdash_is_positional(void) { + char *argv[] = {"program", "--", "a", "--", "b"}; + tl_flag_parse_args(5, argv); + TEST_ASSERT_EQUAL_UINT(3, tl_flag_count_positional()); + TEST_ASSERT_EQUAL_STRING("a", tl_flag_get_positional(0)); + TEST_ASSERT_EQUAL_STRING("--", tl_flag_get_positional(1)); + TEST_ASSERT_EQUAL_STRING("b", tl_flag_get_positional(2)); +} + +static void test_tl_flag_parse_args_positional_mixed_short_long(void) { + char *argv[] = {"program", "pos1", "-v", "--name", "foo", "pos2", "--", "-x", "--y"}; + tl_flag_parse_args(9, argv); + TEST_ASSERT_TRUE(tl_flag_has_flag("-v")); + TEST_ASSERT_EQUAL_STRING("foo", tl_flag_get_value("--name")); + TEST_ASSERT_FALSE(tl_flag_has_flag("-x")); + TEST_ASSERT_FALSE(tl_flag_has_flag("--y")); + TEST_ASSERT_EQUAL_UINT(4, tl_flag_count_positional()); + TEST_ASSERT_EQUAL_STRING("pos1", tl_flag_get_positional(0)); + TEST_ASSERT_EQUAL_STRING("pos2", tl_flag_get_positional(1)); + TEST_ASSERT_EQUAL_STRING("-x", tl_flag_get_positional(2)); + TEST_ASSERT_EQUAL_STRING("--y", tl_flag_get_positional(3)); +} + +static void test_tl_flag_parse_args_positional_only(void) { + char *argv[] = {"program", "a", "b", "c"}; + tl_flag_parse_args(4, argv); + TEST_ASSERT_EQUAL_UINT(0, tl_flag_count_flag("--any")); + TEST_ASSERT_EQUAL_UINT(3, tl_flag_count_positional()); + TEST_ASSERT_EQUAL_STRING("a", tl_flag_get_positional(0)); + TEST_ASSERT_EQUAL_STRING("b", tl_flag_get_positional(1)); + TEST_ASSERT_EQUAL_STRING("c", tl_flag_get_positional(2)); +} + +static void test_tl_flag_parse_args_positional_dashdash_only(void) { + char *argv[] = {"program", "--"}; + tl_flag_parse_args(2, argv); + TEST_ASSERT_EQUAL_UINT(0, tl_flag_count_positional()); +} + +static void test_tl_flag_parse_line_quoted_positional(void) { + TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, + tl_flag_parse_line("prog \"first pos\" --flag v -- \"after dd\" plain")); + TEST_ASSERT_EQUAL_STRING("v", tl_flag_get_value("--flag")); + TEST_ASSERT_EQUAL_UINT(3, tl_flag_count_positional()); + TEST_ASSERT_EQUAL_STRING("first pos", tl_flag_get_positional(0)); + TEST_ASSERT_EQUAL_STRING("after dd", tl_flag_get_positional(1)); + TEST_ASSERT_EQUAL_STRING("plain", tl_flag_get_positional(2)); +} + +static void test_tl_flag_parse_args_long_empty_value(void) { + char *argv[] = {"program", "--foo="}; + tl_flag_parse_args(2, argv); + TEST_ASSERT_TRUE(tl_flag_has_flag("--foo")); + TEST_ASSERT_EQUAL_STRING("", tl_flag_get_value("--foo")); +} + +static void test_tl_flag_parse_args_long_value_contains_equals(void) { + char *argv[] = {"program", "--foo=a=b=c"}; + tl_flag_parse_args(2, argv); + TEST_ASSERT_EQUAL_STRING("a=b=c", tl_flag_get_value("--foo")); +} + +static void test_tl_flag_parse_args_long_space_value_before_terminator(void) { + char *argv[] = {"program", "--foo", "val", "--", "pos"}; + tl_flag_parse_args(5, argv); + TEST_ASSERT_EQUAL_STRING("val", tl_flag_get_value("--foo")); + TEST_ASSERT_EQUAL_UINT(1, tl_flag_count_positional()); + TEST_ASSERT_EQUAL_STRING("pos", tl_flag_get_positional(0)); +} + +static void test_tl_flag_parse_args_short_empty_value(void) { + char *argv[] = {"program", "-o="}; + tl_flag_parse_args(2, argv); + TEST_ASSERT_TRUE(tl_flag_has_flag("-o")); + TEST_ASSERT_EQUAL_STRING("", tl_flag_get_value("-o")); +} + +static void test_tl_flag_parse_args_short_multichar_name(void) { + char *argv[] = {"program", "-xvf", "archive.tar"}; + tl_flag_parse_args(3, argv); + TEST_ASSERT_TRUE(tl_flag_has_flag("-xvf")); + TEST_ASSERT_EQUAL_STRING("archive.tar", tl_flag_get_value("-xvf")); + TEST_ASSERT_FALSE(tl_flag_has_flag("-x")); + TEST_ASSERT_FALSE(tl_flag_has_flag("-v")); + TEST_ASSERT_FALSE(tl_flag_has_flag("-f")); +} + +static void test_tl_flag_parse_args_terminator_at_start(void) { + char *argv[] = {"program", "--", "--foo", "bar"}; + tl_flag_parse_args(4, argv); + TEST_ASSERT_FALSE(tl_flag_has_flag("--foo")); + TEST_ASSERT_EQUAL_UINT(2, tl_flag_count_positional()); + TEST_ASSERT_EQUAL_STRING("--foo", tl_flag_get_positional(0)); + TEST_ASSERT_EQUAL_STRING("bar", tl_flag_get_positional(1)); +} + +static void test_tl_flag_parse_args_null_flag_argument(void) { + char *argv[] = {"program", "--foo=bar"}; + tl_flag_parse_args(2, argv); + TEST_ASSERT_FALSE(tl_flag_has_flag(NULL)); + TEST_ASSERT_NULL(tl_flag_get_value(NULL)); + TEST_ASSERT_EQUAL_UINT(0, tl_flag_count_flag(NULL)); + TEST_ASSERT_NULL(tl_flag_get_value_at(NULL, 0)); +} + +static void test_tl_flag_parse_args_empty_argv(void) { + char *argv[] = {"program"}; + TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_flag_parse_args(1, argv)); + TEST_ASSERT_FALSE(tl_flag_has_flag("--anything")); + TEST_ASSERT_NULL(tl_flag_get_value("--anything")); + TEST_ASSERT_EQUAL_UINT(0, tl_flag_count_flag("--anything")); + TEST_ASSERT_EQUAL_UINT(0, tl_flag_count_positional()); + TEST_ASSERT_NULL(tl_flag_get_positional(0)); +} + +static void test_tl_flag_parse_args_reparse_clears_previous(void) { + char *argv1[] = {"program", "--old=1", "oldpos"}; + tl_flag_parse_args(3, argv1); + TEST_ASSERT_EQUAL_STRING("1", tl_flag_get_value("--old")); + TEST_ASSERT_EQUAL_UINT(1, tl_flag_count_positional()); + + char *argv2[] = {"program", "--new=2"}; + tl_flag_parse_args(2, argv2); + TEST_ASSERT_FALSE(tl_flag_has_flag("--old")); + TEST_ASSERT_EQUAL_STRING("2", tl_flag_get_value("--new")); + TEST_ASSERT_EQUAL_UINT(0, tl_flag_count_positional()); +} + +static void test_tl_flag_parse_args_reparse_line_after_args(void) { + char *argv[] = {"program", "--first=1"}; + tl_flag_parse_args(2, argv); + TEST_ASSERT_EQUAL_STRING("1", tl_flag_get_value("--first")); + + TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_flag_parse_line("program --second=2")); + TEST_ASSERT_FALSE(tl_flag_has_flag("--first")); + TEST_ASSERT_EQUAL_STRING("2", tl_flag_get_value("--second")); +} + +static void test_tl_flag_free_args_idempotent(void) { + tl_flag_free_args(); + tl_flag_free_args(); + char *argv[] = {"program", "--foo"}; + tl_flag_parse_args(2, argv); + tl_flag_free_args(); + tl_flag_free_args(); + TEST_ASSERT_FALSE(tl_flag_has_flag("--foo")); +} + +static void test_tl_flag_count_flag_absent(void) { + char *argv[] = {"program", "--foo"}; + tl_flag_parse_args(2, argv); + TEST_ASSERT_EQUAL_UINT(0, tl_flag_count_flag("--missing")); + TEST_ASSERT_NULL(tl_flag_get_value_at("--missing", 0)); + TEST_ASSERT_NULL(tl_flag_get_value_at("--foo", 5)); +} + +static void test_tl_flag_parse_line_empty(void) { + TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_flag_parse_line("")); + TEST_ASSERT_EQUAL_UINT(0, tl_flag_count_positional()); +} + +static void test_tl_flag_parse_line_whitespace_only(void) { + TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_flag_parse_line(" \t ")); + TEST_ASSERT_EQUAL_UINT(0, tl_flag_count_positional()); +} + +static void test_tl_flag_parse_line_program_only(void) { + TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_flag_parse_line("program")); + TEST_ASSERT_EQUAL_UINT(0, tl_flag_count_positional()); + TEST_ASSERT_FALSE(tl_flag_has_flag("--anything")); +} + +static void test_tl_flag_parse_line_multiple_spaces(void) { + TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_flag_parse_line("prog --foo=1\t\t--bar val")); + TEST_ASSERT_EQUAL_STRING("1", tl_flag_get_value("--foo")); + TEST_ASSERT_EQUAL_STRING("val", tl_flag_get_value("--bar")); +} + +static void test_tl_flag_parse_line_empty_quoted_value(void) { + TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_flag_parse_line("program --foo \"\"")); + TEST_ASSERT_TRUE(tl_flag_has_flag("--foo")); + TEST_ASSERT_EQUAL_STRING("", tl_flag_get_value("--foo")); +} + +static void test_tl_flag_parse_line_escaped_space(void) { + TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_flag_parse_line("program --foo bar\\ baz")); + TEST_ASSERT_EQUAL_STRING("bar baz", tl_flag_get_value("--foo")); +} + +static void test_tl_flag_parse_line_trailing_backslash(void) { + TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_flag_parse_line("program --foo bar\\")); + TEST_ASSERT_EQUAL_STRING("bar\\", tl_flag_get_value("--foo")); +} + +static void test_tl_flag_parse_line_double_backslash(void) { + TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_flag_parse_line("program --foo \"a\\\\b\"")); + TEST_ASSERT_EQUAL_STRING("a\\b", tl_flag_get_value("--foo")); +} + +static void test_tl_flag_parse_args_negative_number_value(void) { + // Space form: -5 is treated as its own flag. Use the = form for negatives. + char *argv1[] = {"program", "--count", "-5"}; + tl_flag_parse_args(3, argv1); + TEST_ASSERT_TRUE(tl_flag_has_flag("--count")); + TEST_ASSERT_NULL(tl_flag_get_value("--count")); + TEST_ASSERT_TRUE(tl_flag_has_flag("-5")); + + // Equals form: unambiguous, works as expected. + char *argv2[] = {"program", "--count=-5"}; + tl_flag_parse_args(2, argv2); + TEST_ASSERT_EQUAL_STRING("-5", tl_flag_get_value("--count")); +} + +static void test_tl_flag_get_arg_index_returns_argv_index(void) { + char *argv[] = {"program", "--global", "command", "subcommand"}; + TEST_ASSERT_EQUAL_UINT(2, tl_flag_get_arg_index(4, argv, "command")); + TEST_ASSERT_EQUAL_UINT(3, tl_flag_get_arg_index(4, argv, "subcommand")); + TEST_ASSERT_EQUAL_UINT(TL_ARG_NOT_FOUND, tl_flag_get_arg_index(4, argv, "missing")); +} + +static void test_tl_flag_get_arg_index_after_starts_after_given_index(void) { + char *argv[] = {"program", "command", "command", "subcommand"}; + size_t command_index = tl_flag_get_arg_index(4, argv, "command"); + TEST_ASSERT_EQUAL_UINT(2, tl_flag_get_arg_index_after(4, argv, "command", command_index)); + TEST_ASSERT_EQUAL_UINT(3, tl_flag_get_arg_index_after(4, argv, "subcommand", command_index)); +} + +static void test_tl_flag_get_arg_index_after_missing_name_returns_not_found(void) { + char *argv[] = {"program", "command"}; + TEST_ASSERT_EQUAL_UINT(TL_ARG_NOT_FOUND, + tl_flag_get_arg_index_after(2, argv, "command", TL_ARG_NOT_FOUND)); + TEST_ASSERT_EQUAL_UINT(TL_ARG_NOT_FOUND, tl_flag_get_arg_index_after(2, argv, "missing", 1)); +} + +static void test_tl_flag_public_type_accepts_tl_flag(void) { + TlFlag flag = {.name = "--flag-bool", .name_len = 11, .value = NULL}; + + TEST_ASSERT_EQUAL_STRING("--flag-bool", flag.name); + TEST_ASSERT_EQUAL_UINT(11, flag.name_len); + TEST_ASSERT_NULL(flag.value); +} + +static void test_tl_flag_parse_args_with_options_null_options_uses_default_parsing(void) { + char *argv[] = {"program", "--flag-bool", "./tmp/example"}; + TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_flag_parse_args_with_options(3, argv, NULL)); + TEST_ASSERT_EQUAL_STRING("./tmp/example", tl_flag_get_value("--flag-bool")); + TEST_ASSERT_EQUAL_UINT(0, tl_flag_count_positional()); +} + +static void test_tl_flag_parse_args_with_options_empty_options_uses_default_parsing(void) { + char *argv[] = {"program", "--flag-bool", "./tmp/example"}; + TlParseOptions options = {.value_flags = NULL, .bool_flags = NULL}; + + TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_flag_parse_args_with_options(3, argv, &options)); + TEST_ASSERT_EQUAL_STRING("./tmp/example", tl_flag_get_value("--flag-bool")); + TEST_ASSERT_EQUAL_UINT(0, tl_flag_count_positional()); +} + +static void test_tl_flag_parse_args_with_options_bool_flag_keeps_positional(void) { + char *argv[] = {"program", "--flag-bool", "./tmp/example"}; + const char *bool_flags[] = {"--flag-bool", NULL}; + TlParseOptions options = {.bool_flags = bool_flags}; + + TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_flag_parse_args_with_options(3, argv, &options)); + TEST_ASSERT_TRUE(tl_flag_has_flag("--flag-bool")); + TEST_ASSERT_NULL(tl_flag_get_value("--flag-bool")); + TEST_ASSERT_EQUAL_STRING("./tmp/example", tl_flag_get_positional(0)); +} + +static void test_tl_flag_parse_args_range_bool_before_positional(void) { + char *argv[] = {"program", "command", "subcommand", "--flag-bool", "./tmp/example"}; + const char *bool_flags[] = {"--flag-bool", NULL}; + TlParseOptions options = {.bool_flags = bool_flags}; + size_t command_index = tl_flag_get_arg_index(5, argv, "command"); + size_t subcommand_index = tl_flag_get_arg_index_after(5, argv, "subcommand", command_index); + + TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, + tl_flag_parse_args_range(5, argv, subcommand_index + 1, 5, &options)); + TEST_ASSERT_TRUE(tl_flag_has_flag("--flag-bool")); + TEST_ASSERT_NULL(tl_flag_get_value("--flag-bool")); + TEST_ASSERT_EQUAL_STRING("./tmp/example", tl_flag_get_positional(0)); +} + +static void test_tl_flag_parse_args_range_bool_after_positional(void) { + char *argv[] = {"program", "command", "subcommand", "./tmp/example", "--flag-bool"}; + const char *bool_flags[] = {"--flag-bool", NULL}; + TlParseOptions options = {.bool_flags = bool_flags}; + + TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_flag_parse_args_range(5, argv, 3, 5, &options)); + TEST_ASSERT_TRUE(tl_flag_has_flag("--flag-bool")); + TEST_ASSERT_EQUAL_STRING("./tmp/example", tl_flag_get_positional(0)); +} + +static void test_tl_flag_parse_args_range_value_flag_space(void) { + char *argv[] = {"program", "command", "subcommand", "--flag-value", "value", "./tmp/example"}; + const char *value_flags[] = {"--flag-value", NULL}; + TlParseOptions options = {.value_flags = value_flags}; + + TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_flag_parse_args_range(6, argv, 3, 6, &options)); + TEST_ASSERT_EQUAL_STRING("value", tl_flag_get_value("--flag-value")); + TEST_ASSERT_EQUAL_STRING("./tmp/example", tl_flag_get_positional(0)); +} + +static void test_tl_flag_parse_args_range_value_flag_equals(void) { + char *argv[] = {"program", "command", "subcommand", "--flag-value=value", "./tmp/example"}; + const char *value_flags[] = {"--flag-value", NULL}; + TlParseOptions options = {.value_flags = value_flags}; + + TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_flag_parse_args_range(5, argv, 3, 5, &options)); + TEST_ASSERT_EQUAL_STRING("value", tl_flag_get_value("--flag-value")); + TEST_ASSERT_EQUAL_STRING("./tmp/example", tl_flag_get_positional(0)); +} + +static void test_tl_flag_parse_args_range_value_flag_without_value_returns_error(void) { + char *argv[] = {"program", "command", "subcommand", "--flag-value"}; + const char *value_flags[] = {"--flag-value", NULL}; + TlParseOptions options = {.value_flags = value_flags}; + + TEST_ASSERT_EQUAL_INT(TL_PARSE_ERROR_MISSING_VALUE, + tl_flag_parse_args_range(4, argv, 3, 4, &options)); + TEST_ASSERT_FALSE(tl_flag_has_flag("--flag-value")); +} + +static void test_tl_flag_parse_args_range_dash_value_requires_equals(void) { + char *argv[] = {"program", "command", "subcommand", "--flag-value", "-5"}; + const char *value_flags[] = {"--flag-value", NULL}; + TlParseOptions options = {.value_flags = value_flags}; + + TEST_ASSERT_EQUAL_INT(TL_PARSE_ERROR_MISSING_VALUE, + tl_flag_parse_args_range(5, argv, 3, 5, &options)); +} + +static void test_tl_flag_parse_args_range_unknown_flag_returns_error(void) { + char *argv[] = {"program", "command", "subcommand", "--unknown", "./tmp/example"}; + const char *bool_flags[] = {"--flag-bool", NULL}; + TlParseOptions options = {.bool_flags = bool_flags}; + + TEST_ASSERT_EQUAL_INT(TL_PARSE_ERROR_UNKNOWN_FLAG, + tl_flag_parse_args_range(5, argv, 3, 5, &options)); +} + +static void test_tl_flag_parse_args_range_conflicting_flag_returns_error(void) { + char *argv[] = {"program", "command", "subcommand", "--flag-bool"}; + const char *value_flags[] = {"--flag-bool", NULL}; + const char *bool_flags[] = {"--flag-bool", NULL}; + TlParseOptions options = {.value_flags = value_flags, .bool_flags = bool_flags}; + + TEST_ASSERT_EQUAL_INT(TL_PARSE_ERROR_CONFLICTING_FLAG, + tl_flag_parse_args_range(4, argv, 3, 4, &options)); +} + +static void test_tl_flag_parse_args_range_invalid_bounds_returns_error(void) { + char *argv[] = {"program", "command"}; + TEST_ASSERT_EQUAL_INT(TL_PARSE_ERROR_INVALID_RANGE, + tl_flag_parse_args_range(2, argv, 3, 3, NULL)); + TEST_ASSERT_EQUAL_INT(TL_PARSE_ERROR_INVALID_RANGE, + tl_flag_parse_args_range(2, argv, 1, 3, NULL)); + TEST_ASSERT_EQUAL_INT(TL_PARSE_ERROR_INVALID_RANGE, + tl_flag_parse_args_range(2, argv, 2, 1, NULL)); + TEST_ASSERT_EQUAL_INT(TL_PARSE_ERROR_INVALID_RANGE, + tl_flag_parse_args_range(2, argv, TL_ARG_NOT_FOUND, 2, NULL)); + TEST_ASSERT_EQUAL_INT(TL_PARSE_ERROR_INVALID_RANGE, + tl_flag_parse_args_range(2, argv, 1, TL_ARG_NOT_FOUND, NULL)); +} + +static void test_tl_flag_parse_args_range_invalid_range_clears_previous_state(void) { + char *argv1[] = {"program", "--old=1", "oldpos"}; + char *argv2[] = {"program", "command"}; + + tl_flag_parse_args(3, argv1); + TEST_ASSERT_TRUE(tl_flag_has_flag("--old")); + TEST_ASSERT_EQUAL_UINT(1, tl_flag_count_positional()); + + TEST_ASSERT_EQUAL_INT(TL_PARSE_ERROR_INVALID_RANGE, + tl_flag_parse_args_range(2, argv2, 1, 3, NULL)); + TEST_ASSERT_FALSE(tl_flag_has_flag("--old")); + TEST_ASSERT_EQUAL_UINT(0, tl_flag_count_positional()); +} + +static void test_tl_flag_parse_args_range_empty_range_returns_ok(void) { + char *argv[] = {"program", "command"}; + TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_flag_parse_args_range(2, argv, 2, 2, NULL)); + TEST_ASSERT_EQUAL_UINT(0, tl_flag_count_flag("--anything")); + TEST_ASSERT_EQUAL_UINT(0, tl_flag_count_positional()); +} + +static void test_tl_flag_parse_args_range_empty_range_clears_previous_state(void) { + char *argv1[] = {"program", "--old=1", "oldpos"}; + char *argv2[] = {"program", "command"}; + + tl_flag_parse_args(3, argv1); + TEST_ASSERT_TRUE(tl_flag_has_flag("--old")); + TEST_ASSERT_EQUAL_UINT(1, tl_flag_count_positional()); + + TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_flag_parse_args_range(2, argv2, 2, 2, NULL)); + TEST_ASSERT_FALSE(tl_flag_has_flag("--old")); + TEST_ASSERT_EQUAL_UINT(0, tl_flag_count_positional()); +} + +static void test_tl_flag_parse_args_range_can_include_argv_zero(void) { + char *argv[] = {"program", "command", "--flag-bool"}; + const char *bool_flags[] = {"--flag-bool", NULL}; + TlParseOptions options = {.bool_flags = bool_flags}; + + TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_flag_parse_args_range(3, argv, 0, 3, &options)); + TEST_ASSERT_EQUAL_STRING("program", tl_flag_get_positional(0)); + TEST_ASSERT_EQUAL_STRING("command", tl_flag_get_positional(1)); + TEST_ASSERT_TRUE(tl_flag_has_flag("--flag-bool")); +} + +static void test_tl_flag_parse_args_range_terminator_keeps_positionals(void) { + char *argv[] = {"program", "command", "subcommand", "--", "--unknown", "./tmp/example"}; + const char *bool_flags[] = {"--flag-bool", NULL}; + TlParseOptions options = {.bool_flags = bool_flags}; + + TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_flag_parse_args_range(6, argv, 3, 6, &options)); + TEST_ASSERT_EQUAL_STRING("--unknown", tl_flag_get_positional(0)); + TEST_ASSERT_EQUAL_STRING("./tmp/example", tl_flag_get_positional(1)); +} + +static void test_tl_flag_parse_args_null_argv(void) { + TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_flag_parse_args(0, NULL)); + TEST_ASSERT_EQUAL_UINT(0, tl_flag_count_positional()); + TEST_ASSERT_FALSE(tl_flag_has_flag("--anything")); + + TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_flag_parse_args(5, NULL)); + TEST_ASSERT_EQUAL_UINT(0, tl_flag_count_positional()); + TEST_ASSERT_FALSE(tl_flag_has_flag("--anything")); +} + +static void test_tl_flag_has_positional(void) { + char *argv[] = {"program", "serve", "-f", "file"}; + tl_flag_parse_args(4, argv); + TEST_ASSERT_TRUE(tl_flag_has_positional("serve")); + TEST_ASSERT_FALSE(tl_flag_has_positional("missing")); +} + +static void test_tl_flag_has_positional_multiple(void) { + char *argv[] = {"program", "remote", "add", "origin", "--verbose"}; + tl_flag_parse_args(5, argv); + TEST_ASSERT_TRUE(tl_flag_has_positional("remote")); + TEST_ASSERT_TRUE(tl_flag_has_positional("add")); + TEST_ASSERT_TRUE(tl_flag_has_positional("origin")); + TEST_ASSERT_FALSE(tl_flag_has_positional("--verbose")); +} + +static void test_tl_flag_has_positional_after_terminator(void) { + char *argv[] = {"program", "cmd", "--", "--foo", "bar"}; + tl_flag_parse_args(5, argv); + TEST_ASSERT_TRUE(tl_flag_has_positional("cmd")); + TEST_ASSERT_TRUE(tl_flag_has_positional("--foo")); + TEST_ASSERT_TRUE(tl_flag_has_positional("bar")); +} + +static void test_tl_flag_has_positional_none(void) { + char *argv[] = {"program", "--flag"}; + tl_flag_parse_args(2, argv); + TEST_ASSERT_FALSE(tl_flag_has_positional("anything")); +} + +static void test_tl_flag_has_positional_null(void) { + char *argv[] = {"program", "cmd"}; + tl_flag_parse_args(2, argv); + TEST_ASSERT_FALSE(tl_flag_has_positional(NULL)); +} + +int main(void) { + UNITY_BEGIN(); + + RUN_TEST(test_tl_flag_parse_args_single_flag_sets_flag); + RUN_TEST(test_tl_flag_has_flag_existing_flag_returns_true); + RUN_TEST(test_tl_flag_get_value_equals_value_returns_value); + RUN_TEST(test_tl_flag_get_value_space); + RUN_TEST(test_tl_flag_get_value_partial_name_returns_null); + RUN_TEST(test_tl_flag_parse_args_repeated_flag_equals); + RUN_TEST(test_tl_flag_parse_args_repeated_flag_mixed); + RUN_TEST(test_tl_flag_parse_args_repeated_boolean_flag); + RUN_TEST(test_tl_flag_parse_args_adjacent_space_flags); + RUN_TEST(test_tl_flag_parse_args_space_flag_trailing_boolean); + RUN_TEST(test_tl_flag_parse_args_positional_terminator); + RUN_TEST(test_tl_flag_parse_args_positional_interleaved); + RUN_TEST(test_tl_flag_parse_args_quoted_value_from_argv); + RUN_TEST(test_tl_flag_parse_line_quoted); + RUN_TEST(test_tl_flag_parse_line_escape); + RUN_TEST(test_tl_flag_parse_line_full); + RUN_TEST(test_tl_flag_parse_line_unterminated); + RUN_TEST(test_tl_flag_parse_line_null); + RUN_TEST(test_tl_flag_parse_args_short_flag); + RUN_TEST(test_tl_flag_parse_args_short_flag_value); + RUN_TEST(test_tl_flag_parse_args_short_flag_equals); + RUN_TEST(test_tl_flag_parse_args_bare_dash_is_positional); + RUN_TEST(test_tl_flag_parse_args_short_flag_exact_match); + RUN_TEST(test_tl_flag_parse_args_short_repeated_boolean); + RUN_TEST(test_tl_flag_parse_args_short_repeated_mixed); + RUN_TEST(test_tl_flag_parse_args_short_adjacent); + RUN_TEST(test_tl_flag_parse_args_short_trailing_boolean); + RUN_TEST(test_tl_flag_parse_args_short_value_is_bare_dash); + RUN_TEST(test_tl_flag_parse_args_short_long_mixed); + RUN_TEST(test_tl_flag_parse_args_short_followed_by_long); + RUN_TEST(test_tl_flag_parse_args_positional_dashdash_trailing_empty); + RUN_TEST(test_tl_flag_parse_args_positional_second_dashdash_is_positional); + RUN_TEST(test_tl_flag_parse_args_positional_mixed_short_long); + RUN_TEST(test_tl_flag_parse_args_positional_only); + RUN_TEST(test_tl_flag_parse_args_positional_dashdash_only); + RUN_TEST(test_tl_flag_parse_line_quoted_positional); + RUN_TEST(test_tl_flag_parse_args_long_empty_value); + RUN_TEST(test_tl_flag_parse_args_long_value_contains_equals); + RUN_TEST(test_tl_flag_parse_args_long_space_value_before_terminator); + RUN_TEST(test_tl_flag_parse_args_short_empty_value); + RUN_TEST(test_tl_flag_parse_args_short_multichar_name); + RUN_TEST(test_tl_flag_parse_args_terminator_at_start); + RUN_TEST(test_tl_flag_parse_args_null_flag_argument); + RUN_TEST(test_tl_flag_parse_args_empty_argv); + RUN_TEST(test_tl_flag_parse_args_reparse_clears_previous); + RUN_TEST(test_tl_flag_parse_args_reparse_line_after_args); + RUN_TEST(test_tl_flag_free_args_idempotent); + RUN_TEST(test_tl_flag_count_flag_absent); + RUN_TEST(test_tl_flag_parse_line_empty); + RUN_TEST(test_tl_flag_parse_line_whitespace_only); + RUN_TEST(test_tl_flag_parse_line_program_only); + RUN_TEST(test_tl_flag_parse_line_multiple_spaces); + RUN_TEST(test_tl_flag_parse_line_empty_quoted_value); + RUN_TEST(test_tl_flag_parse_line_escaped_space); + RUN_TEST(test_tl_flag_parse_line_trailing_backslash); + RUN_TEST(test_tl_flag_parse_line_double_backslash); + RUN_TEST(test_tl_flag_parse_args_negative_number_value); + RUN_TEST(test_tl_flag_get_arg_index_returns_argv_index); + RUN_TEST(test_tl_flag_get_arg_index_after_starts_after_given_index); + RUN_TEST(test_tl_flag_get_arg_index_after_missing_name_returns_not_found); + RUN_TEST(test_tl_flag_public_type_accepts_tl_flag); + RUN_TEST(test_tl_flag_parse_args_with_options_null_options_uses_default_parsing); + RUN_TEST(test_tl_flag_parse_args_with_options_empty_options_uses_default_parsing); + RUN_TEST(test_tl_flag_parse_args_with_options_bool_flag_keeps_positional); + RUN_TEST(test_tl_flag_parse_args_range_bool_before_positional); + RUN_TEST(test_tl_flag_parse_args_range_bool_after_positional); + RUN_TEST(test_tl_flag_parse_args_range_value_flag_space); + RUN_TEST(test_tl_flag_parse_args_range_value_flag_equals); + RUN_TEST(test_tl_flag_parse_args_range_value_flag_without_value_returns_error); + RUN_TEST(test_tl_flag_parse_args_range_dash_value_requires_equals); + RUN_TEST(test_tl_flag_parse_args_range_unknown_flag_returns_error); + RUN_TEST(test_tl_flag_parse_args_range_conflicting_flag_returns_error); + RUN_TEST(test_tl_flag_parse_args_range_invalid_bounds_returns_error); + RUN_TEST(test_tl_flag_parse_args_range_invalid_range_clears_previous_state); + RUN_TEST(test_tl_flag_parse_args_range_empty_range_returns_ok); + RUN_TEST(test_tl_flag_parse_args_range_empty_range_clears_previous_state); + RUN_TEST(test_tl_flag_parse_args_range_can_include_argv_zero); + RUN_TEST(test_tl_flag_parse_args_range_terminator_keeps_positionals); + RUN_TEST(test_tl_flag_parse_args_null_argv); + RUN_TEST(test_tl_flag_has_positional); + RUN_TEST(test_tl_flag_has_positional_multiple); + RUN_TEST(test_tl_flag_has_positional_after_terminator); + RUN_TEST(test_tl_flag_has_positional_none); + RUN_TEST(test_tl_flag_has_positional_null); + + return UNITY_END(); +} diff --git a/tests/unit/test_test.c b/tests/api/test_api_test.c similarity index 65% rename from tests/unit/test_test.c rename to tests/api/test_api_test.c index c31626f..94875b0 100644 --- a/tests/unit/test_test.c +++ b/tests/api/test_api_test.c @@ -10,11 +10,11 @@ void tearDown(void) { // Teardown code if needed } -static void test_tl_timespec_diff_ns(void) { +static void test_tl_test_get_timespec_diff_ns_returns_nanoseconds(void) { struct timespec start = {.tv_sec = 1, .tv_nsec = 500000000}; struct timespec end = {.tv_sec = 2, .tv_nsec = 200000000}; - long long diff_ns = tl_timespec_diff_ns(&start, &end); + long long diff_ns = tl_test_get_timespec_diff_ns(&start, &end); TEST_ASSERT_EQUAL(700000000, diff_ns); } @@ -22,7 +22,7 @@ static void test_tl_timespec_diff_ns(void) { int main(void) { UNITY_BEGIN(); - RUN_TEST(test_tl_timespec_diff_ns); + RUN_TEST(test_tl_test_get_timespec_diff_ns_returns_nanoseconds); return UNITY_END(); } diff --git a/tests/unit/app_test.c b/tests/unit/app_test.c deleted file mode 100644 index 97163f0..0000000 --- a/tests/unit/app_test.c +++ /dev/null @@ -1,34 +0,0 @@ -#include "tl_app.h" -#include "tl_flag.h" -#include "unity.h" - -void setUp(void) { - // Setup code if needed -} - -void tearDown(void) { - tl_free_args(); -} - -static void test_tl_init_app(void) { - char *argv[] = {"program", "--debug-level=2"}; - tl_init_app(2, argv); - TEST_ASSERT_TRUE(tl_lookup_flag("--debug-level")); - TEST_ASSERT_EQUAL_STRING("2", tl_get_flag("--debug-level")); -} - -static void test_tl_init_app_space(void) { - char *argv[] = {"program", "--debug-level", "3"}; - tl_init_app(3, argv); - TEST_ASSERT_TRUE(tl_lookup_flag("--debug-level")); - TEST_ASSERT_EQUAL_STRING("3", tl_get_flag("--debug-level")); -} - -int main(void) { - UNITY_BEGIN(); - - RUN_TEST(test_tl_init_app); - RUN_TEST(test_tl_init_app_space); - - return UNITY_END(); -} diff --git a/tests/unit/config_test.c b/tests/unit/config_test.c deleted file mode 100644 index eca5664..0000000 --- a/tests/unit/config_test.c +++ /dev/null @@ -1,47 +0,0 @@ -#include "tl_config.h" -#include "unity.h" - -void setUp(void) { - // Setup code if needed -} - -void tearDown(void) { - // Teardown code if needed -} - -static void test_tl_get_debug_level(void) { - tl_set_debug_level(3); - TEST_ASSERT_EQUAL(3, tl_get_debug_level()); -} - -static void test_tl_set_debug_level(void) { - TEST_ASSERT_TRUE(tl_set_debug_level(5)); - TEST_ASSERT_EQUAL(5, tl_get_debug_level()); -} - -static void test_tl_neon_available(void) { -#if TL_NEON_AVAILABLE - TEST_ASSERT_TRUE(tl_neon_available()); -#else - TEST_ASSERT_FALSE(tl_neon_available()); -#endif -} - -static void test_tl_cmsis_dsp_available(void) { -#if TL_CMSIS_DSP_AVAILABLE - TEST_ASSERT_TRUE(tl_cmsis_dsp_available()); -#else - TEST_ASSERT_FALSE(tl_cmsis_dsp_available()); -#endif -} - -int main(void) { - UNITY_BEGIN(); - - RUN_TEST(test_tl_get_debug_level); - RUN_TEST(test_tl_set_debug_level); - RUN_TEST(test_tl_neon_available); - RUN_TEST(test_tl_cmsis_dsp_available); - - return UNITY_END(); -} diff --git a/tests/unit/error_test.c b/tests/unit/error_test.c deleted file mode 100644 index 13b8d71..0000000 --- a/tests/unit/error_test.c +++ /dev/null @@ -1,48 +0,0 @@ -#include "tl_error.h" -#include "unity.h" -#include -#include - -void setUp(void) { - // Setup code if needed -} - -void tearDown(void) { - // Teardown code if needed -} - -static void test_tl_error_set_with_fixed_message(void) { - TLError error = {0}; - tl_error_set(&error, TL_ERROR_INTERNAL, "fixed error message"); - - TEST_ASSERT_EQUAL(TL_ERROR_INTERNAL, error.code); - TEST_ASSERT_NOT_NULL(error.message); - TEST_ASSERT_EQUAL_STRING("fixed error message", error.message); - - free((void *)error.message); -} - -static void test_tl_error_set_with_formatted_message(void) { - TLError error = {0}; - tl_error_set(&error, TL_ERROR_NOT_FOUND, "formatted error: %d", 42); - - TEST_ASSERT_EQUAL(TL_ERROR_NOT_FOUND, error.code); - TEST_ASSERT_NOT_NULL(error.message); - TEST_ASSERT_EQUAL_STRING("formatted error: 42", error.message); - - free((void *)error.message); -} - -static void test_tl_error_set_with_null_error(void) { - tl_error_set(NULL, TL_ERROR_NOT_READY, "this should not crash"); -} - -int main(void) { - UNITY_BEGIN(); - - RUN_TEST(test_tl_error_set_with_fixed_message); - RUN_TEST(test_tl_error_set_with_formatted_message); - RUN_TEST(test_tl_error_set_with_null_error); - - return UNITY_END(); -} diff --git a/tests/unit/flag_test.c b/tests/unit/flag_test.c deleted file mode 100644 index 2882b6b..0000000 --- a/tests/unit/flag_test.c +++ /dev/null @@ -1,806 +0,0 @@ -#include "tl_flag.h" -#include "unity.h" - -void setUp(void) { - // Setup code if needed -} - -void tearDown(void) { - tl_free_args(); -} - -static void test_tl_parse_args(void) { - char *argv[] = {"program", "--test-flag"}; - TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_parse_args(2, argv)); - TEST_ASSERT_TRUE(tl_lookup_flag("--test-flag")); -} - -static void test_tl_lookup_flag(void) { - char *argv[] = {"program", "--test-flag"}; - tl_parse_args(2, argv); - TEST_ASSERT_TRUE(tl_lookup_flag("--test-flag")); - TEST_ASSERT_FALSE(tl_lookup_flag("--nonexistent-flag")); -} - -static void test_tl_get_flag(void) { - char *argv[] = {"program", "--key=value"}; - tl_parse_args(2, argv); - TEST_ASSERT_EQUAL_STRING("value", tl_get_flag("--key")); - TEST_ASSERT_NULL(tl_get_flag("--nonexistent-key")); -} - -static void test_tl_get_flag_space(void) { - char *argv[] = {"program", "--key", "value"}; - tl_parse_args(3, argv); - TEST_ASSERT_EQUAL_STRING("value", tl_get_flag("--key")); -} - -static void test_tl_flag_exact_match(void) { - char *argv[] = {"program", "--foobar=1"}; - tl_parse_args(2, argv); - TEST_ASSERT_FALSE(tl_lookup_flag("--foo")); - TEST_ASSERT_NULL(tl_get_flag("--foo")); - TEST_ASSERT_EQUAL_STRING("1", tl_get_flag("--foobar")); -} - -static void test_tl_repeated_flag_equals(void) { - char *argv[] = {"program", "--foo=x", "--foo=y", "--foo=z"}; - tl_parse_args(4, argv); - TEST_ASSERT_EQUAL_UINT(3, tl_count_flag("--foo")); - TEST_ASSERT_EQUAL_STRING("x", tl_get_flag_at("--foo", 0)); - TEST_ASSERT_EQUAL_STRING("y", tl_get_flag_at("--foo", 1)); - TEST_ASSERT_EQUAL_STRING("z", tl_get_flag_at("--foo", 2)); - TEST_ASSERT_NULL(tl_get_flag_at("--foo", 3)); - TEST_ASSERT_EQUAL_STRING("x", tl_get_flag("--foo")); -} - -static void test_tl_repeated_flag_mixed(void) { - char *argv[] = {"program", "--foo=x", "--foo", "y", "--foo=z"}; - tl_parse_args(5, argv); - TEST_ASSERT_EQUAL_UINT(3, tl_count_flag("--foo")); - TEST_ASSERT_EQUAL_STRING("x", tl_get_flag_at("--foo", 0)); - TEST_ASSERT_EQUAL_STRING("y", tl_get_flag_at("--foo", 1)); - TEST_ASSERT_EQUAL_STRING("z", tl_get_flag_at("--foo", 2)); -} - -static void test_tl_repeated_boolean_flag(void) { - char *argv[] = {"program", "--verbose", "--verbose", "--verbose"}; - tl_parse_args(4, argv); - TEST_ASSERT_EQUAL_UINT(3, tl_count_flag("--verbose")); - TEST_ASSERT_NULL(tl_get_flag_at("--verbose", 0)); - TEST_ASSERT_NULL(tl_get_flag_at("--verbose", 1)); - TEST_ASSERT_NULL(tl_get_flag_at("--verbose", 2)); -} - -static void test_tl_adjacent_space_flags(void) { - char *argv[] = {"program", "--foo", "x", "--bar", "y"}; - tl_parse_args(5, argv); - TEST_ASSERT_EQUAL_STRING("x", tl_get_flag("--foo")); - TEST_ASSERT_EQUAL_STRING("y", tl_get_flag("--bar")); -} - -static void test_tl_space_flag_trailing_boolean(void) { - char *argv[] = {"program", "--foo", "x", "--bar"}; - tl_parse_args(4, argv); - TEST_ASSERT_EQUAL_STRING("x", tl_get_flag("--foo")); - TEST_ASSERT_TRUE(tl_lookup_flag("--bar")); - TEST_ASSERT_NULL(tl_get_flag("--bar")); -} - -static void test_tl_positional_terminator(void) { - char *argv[] = {"program", "command", "--foo", "--", "--baz", "--qux"}; - tl_parse_args(6, argv); - TEST_ASSERT_TRUE(tl_lookup_flag("--foo")); - TEST_ASSERT_NULL(tl_get_flag("--foo")); - TEST_ASSERT_FALSE(tl_lookup_flag("--baz")); - TEST_ASSERT_FALSE(tl_lookup_flag("--qux")); - TEST_ASSERT_EQUAL_UINT(3, tl_count_positional()); - TEST_ASSERT_EQUAL_STRING("command", tl_get_positional(0)); - TEST_ASSERT_EQUAL_STRING("--baz", tl_get_positional(1)); - TEST_ASSERT_EQUAL_STRING("--qux", tl_get_positional(2)); - TEST_ASSERT_NULL(tl_get_positional(3)); -} - -static void test_tl_positional_interleaved(void) { - char *argv[] = {"program", "foo", "--flag", "val", "bar"}; - tl_parse_args(5, argv); - TEST_ASSERT_EQUAL_STRING("val", tl_get_flag("--flag")); - 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_quoted_value_from_argv(void) { - char *argv[] = {"program", "--foo", "bar baz qux"}; - tl_parse_args(3, argv); - TEST_ASSERT_EQUAL_STRING("bar baz qux", tl_get_flag("--foo")); -} - -static void test_tl_parse_line_quoted(void) { - TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_parse_line("program --foo \"bar baz qux\"")); - TEST_ASSERT_EQUAL_STRING("bar baz qux", tl_get_flag("--foo")); -} - -static void test_tl_parse_line_escape(void) { - TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_parse_line("program --foo \"a\\\"b\"")); - TEST_ASSERT_EQUAL_STRING("a\"b", tl_get_flag("--foo")); -} - -static void test_tl_parse_line_full(void) { - TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, - tl_parse_line("prog cmd --foo=1 --foo 2 --bar \"x y\" -- --baz")); - TEST_ASSERT_EQUAL_UINT(2, tl_count_flag("--foo")); - TEST_ASSERT_EQUAL_STRING("1", tl_get_flag_at("--foo", 0)); - TEST_ASSERT_EQUAL_STRING("2", tl_get_flag_at("--foo", 1)); - TEST_ASSERT_EQUAL_STRING("x y", tl_get_flag("--bar")); - TEST_ASSERT_EQUAL_UINT(2, tl_count_positional()); - TEST_ASSERT_EQUAL_STRING("cmd", tl_get_positional(0)); - TEST_ASSERT_EQUAL_STRING("--baz", tl_get_positional(1)); -} - -static void test_tl_parse_line_unterminated(void) { - TEST_ASSERT_EQUAL_INT(TL_PARSE_ERROR_UNTERMINATED_QUOTE, - tl_parse_line("program --foo \"unterminated")); -} - -static void test_tl_parse_line_null(void) { - TEST_ASSERT_EQUAL_INT(TL_PARSE_ERROR_INVALID_INPUT, tl_parse_line(NULL)); -} - -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_EQUAL_INT(TL_PARSE_OK, - tl_parse_line("prog \"first pos\" --flag v -- \"after dd\" plain")); - TEST_ASSERT_EQUAL_STRING("v", tl_get_flag("--flag")); - TEST_ASSERT_EQUAL_UINT(3, tl_count_positional()); - TEST_ASSERT_EQUAL_STRING("first pos", tl_get_positional(0)); - TEST_ASSERT_EQUAL_STRING("after dd", tl_get_positional(1)); - 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"}; - TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, 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_EQUAL_INT(TL_PARSE_OK, 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_EQUAL_INT(TL_PARSE_OK, tl_parse_line("")); - TEST_ASSERT_EQUAL_UINT(0, tl_count_positional()); -} - -static void test_tl_parse_line_whitespace_only(void) { - TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_parse_line(" \t ")); - TEST_ASSERT_EQUAL_UINT(0, tl_count_positional()); -} - -static void test_tl_parse_line_program_only(void) { - TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, 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_EQUAL_INT(TL_PARSE_OK, 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_EQUAL_INT(TL_PARSE_OK, 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_EQUAL_INT(TL_PARSE_OK, 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_EQUAL_INT(TL_PARSE_OK, 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_EQUAL_INT(TL_PARSE_OK, 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_arg_index_returns_argv_index(void) { - char *argv[] = {"program", "--global", "command", "subcommand"}; - TEST_ASSERT_EQUAL_UINT(2, tl_arg_index(4, argv, "command")); - TEST_ASSERT_EQUAL_UINT(3, tl_arg_index(4, argv, "subcommand")); - TEST_ASSERT_EQUAL_UINT(TL_ARG_NOT_FOUND, tl_arg_index(4, argv, "missing")); -} - -static void test_tl_arg_index_after_starts_after_given_index(void) { - char *argv[] = {"program", "command", "command", "subcommand"}; - size_t command_index = tl_arg_index(4, argv, "command"); - TEST_ASSERT_EQUAL_UINT(2, tl_arg_index_after(4, argv, "command", command_index)); - TEST_ASSERT_EQUAL_UINT(3, tl_arg_index_after(4, argv, "subcommand", command_index)); -} - -static void test_tl_arg_index_after_missing_name_returns_not_found(void) { - char *argv[] = {"program", "command"}; - TEST_ASSERT_EQUAL_UINT(TL_ARG_NOT_FOUND, - tl_arg_index_after(2, argv, "command", TL_ARG_NOT_FOUND)); - TEST_ASSERT_EQUAL_UINT(TL_ARG_NOT_FOUND, tl_arg_index_after(2, argv, "missing", 1)); -} - -static void test_tl_flag_public_type_accepts_tl_flag(void) { - TlFlag flag = {.name = "--flag-bool", .name_len = 11, .value = NULL}; - - TEST_ASSERT_EQUAL_STRING("--flag-bool", flag.name); - TEST_ASSERT_EQUAL_UINT(11, flag.name_len); - TEST_ASSERT_NULL(flag.value); -} - -static void test_tl_parse_args_ex_null_options_uses_default_parsing(void) { - char *argv[] = {"program", "--flag-bool", "./tmp/example"}; - TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_parse_args_ex(3, argv, NULL)); - TEST_ASSERT_EQUAL_STRING("./tmp/example", tl_get_flag("--flag-bool")); - TEST_ASSERT_EQUAL_UINT(0, tl_count_positional()); -} - -static void test_tl_parse_args_ex_empty_options_uses_default_parsing(void) { - char *argv[] = {"program", "--flag-bool", "./tmp/example"}; - TlParseOptions options = {.value_flags = NULL, .bool_flags = NULL}; - - TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_parse_args_ex(3, argv, &options)); - TEST_ASSERT_EQUAL_STRING("./tmp/example", tl_get_flag("--flag-bool")); - TEST_ASSERT_EQUAL_UINT(0, tl_count_positional()); -} - -static void test_tl_parse_args_ex_bool_flag_keeps_positional(void) { - char *argv[] = {"program", "--flag-bool", "./tmp/example"}; - const char *bool_flags[] = {"--flag-bool", NULL}; - TlParseOptions options = {.bool_flags = bool_flags}; - - TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_parse_args_ex(3, argv, &options)); - TEST_ASSERT_TRUE(tl_lookup_flag("--flag-bool")); - TEST_ASSERT_NULL(tl_get_flag("--flag-bool")); - TEST_ASSERT_EQUAL_STRING("./tmp/example", tl_get_positional(0)); -} - -static void test_tl_parse_args_range_bool_before_positional(void) { - char *argv[] = {"program", "command", "subcommand", "--flag-bool", "./tmp/example"}; - const char *bool_flags[] = {"--flag-bool", NULL}; - TlParseOptions options = {.bool_flags = bool_flags}; - size_t command_index = tl_arg_index(5, argv, "command"); - size_t subcommand_index = tl_arg_index_after(5, argv, "subcommand", command_index); - - TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, - tl_parse_args_range(5, argv, subcommand_index + 1, 5, &options)); - TEST_ASSERT_TRUE(tl_lookup_flag("--flag-bool")); - TEST_ASSERT_NULL(tl_get_flag("--flag-bool")); - TEST_ASSERT_EQUAL_STRING("./tmp/example", tl_get_positional(0)); -} - -static void test_tl_parse_args_range_bool_after_positional(void) { - char *argv[] = {"program", "command", "subcommand", "./tmp/example", "--flag-bool"}; - const char *bool_flags[] = {"--flag-bool", NULL}; - TlParseOptions options = {.bool_flags = bool_flags}; - - TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_parse_args_range(5, argv, 3, 5, &options)); - TEST_ASSERT_TRUE(tl_lookup_flag("--flag-bool")); - TEST_ASSERT_EQUAL_STRING("./tmp/example", tl_get_positional(0)); -} - -static void test_tl_parse_args_range_value_flag_space(void) { - char *argv[] = {"program", "command", "subcommand", "--flag-value", "value", "./tmp/example"}; - const char *value_flags[] = {"--flag-value", NULL}; - TlParseOptions options = {.value_flags = value_flags}; - - TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_parse_args_range(6, argv, 3, 6, &options)); - TEST_ASSERT_EQUAL_STRING("value", tl_get_flag("--flag-value")); - TEST_ASSERT_EQUAL_STRING("./tmp/example", tl_get_positional(0)); -} - -static void test_tl_parse_args_range_value_flag_equals(void) { - char *argv[] = {"program", "command", "subcommand", "--flag-value=value", "./tmp/example"}; - const char *value_flags[] = {"--flag-value", NULL}; - TlParseOptions options = {.value_flags = value_flags}; - - TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_parse_args_range(5, argv, 3, 5, &options)); - TEST_ASSERT_EQUAL_STRING("value", tl_get_flag("--flag-value")); - TEST_ASSERT_EQUAL_STRING("./tmp/example", tl_get_positional(0)); -} - -static void test_tl_parse_args_range_value_flag_without_value_returns_error(void) { - char *argv[] = {"program", "command", "subcommand", "--flag-value"}; - const char *value_flags[] = {"--flag-value", NULL}; - TlParseOptions options = {.value_flags = value_flags}; - - TEST_ASSERT_EQUAL_INT(TL_PARSE_ERROR_MISSING_VALUE, - tl_parse_args_range(4, argv, 3, 4, &options)); - TEST_ASSERT_FALSE(tl_lookup_flag("--flag-value")); -} - -static void test_tl_parse_args_range_dash_value_requires_equals(void) { - char *argv[] = {"program", "command", "subcommand", "--flag-value", "-5"}; - const char *value_flags[] = {"--flag-value", NULL}; - TlParseOptions options = {.value_flags = value_flags}; - - TEST_ASSERT_EQUAL_INT(TL_PARSE_ERROR_MISSING_VALUE, - tl_parse_args_range(5, argv, 3, 5, &options)); -} - -static void test_tl_parse_args_range_unknown_flag_returns_error(void) { - char *argv[] = {"program", "command", "subcommand", "--unknown", "./tmp/example"}; - const char *bool_flags[] = {"--flag-bool", NULL}; - TlParseOptions options = {.bool_flags = bool_flags}; - - TEST_ASSERT_EQUAL_INT(TL_PARSE_ERROR_UNKNOWN_FLAG, - tl_parse_args_range(5, argv, 3, 5, &options)); -} - -static void test_tl_parse_args_range_conflicting_flag_returns_error(void) { - char *argv[] = {"program", "command", "subcommand", "--flag-bool"}; - const char *value_flags[] = {"--flag-bool", NULL}; - const char *bool_flags[] = {"--flag-bool", NULL}; - TlParseOptions options = {.value_flags = value_flags, .bool_flags = bool_flags}; - - TEST_ASSERT_EQUAL_INT(TL_PARSE_ERROR_CONFLICTING_FLAG, - tl_parse_args_range(4, argv, 3, 4, &options)); -} - -static void test_tl_parse_args_range_invalid_bounds_returns_error(void) { - char *argv[] = {"program", "command"}; - TEST_ASSERT_EQUAL_INT(TL_PARSE_ERROR_INVALID_RANGE, tl_parse_args_range(2, argv, 3, 3, NULL)); - TEST_ASSERT_EQUAL_INT(TL_PARSE_ERROR_INVALID_RANGE, tl_parse_args_range(2, argv, 1, 3, NULL)); - TEST_ASSERT_EQUAL_INT(TL_PARSE_ERROR_INVALID_RANGE, tl_parse_args_range(2, argv, 2, 1, NULL)); - TEST_ASSERT_EQUAL_INT(TL_PARSE_ERROR_INVALID_RANGE, - tl_parse_args_range(2, argv, TL_ARG_NOT_FOUND, 2, NULL)); - TEST_ASSERT_EQUAL_INT(TL_PARSE_ERROR_INVALID_RANGE, - tl_parse_args_range(2, argv, 1, TL_ARG_NOT_FOUND, NULL)); -} - -static void test_tl_parse_args_range_invalid_range_clears_previous_state(void) { - char *argv1[] = {"program", "--old=1", "oldpos"}; - char *argv2[] = {"program", "command"}; - - tl_parse_args(3, argv1); - TEST_ASSERT_TRUE(tl_lookup_flag("--old")); - TEST_ASSERT_EQUAL_UINT(1, tl_count_positional()); - - TEST_ASSERT_EQUAL_INT(TL_PARSE_ERROR_INVALID_RANGE, tl_parse_args_range(2, argv2, 1, 3, NULL)); - TEST_ASSERT_FALSE(tl_lookup_flag("--old")); - TEST_ASSERT_EQUAL_UINT(0, tl_count_positional()); -} - -static void test_tl_parse_args_range_empty_range_returns_ok(void) { - char *argv[] = {"program", "command"}; - TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_parse_args_range(2, argv, 2, 2, NULL)); - TEST_ASSERT_EQUAL_UINT(0, tl_count_flag("--anything")); - TEST_ASSERT_EQUAL_UINT(0, tl_count_positional()); -} - -static void test_tl_parse_args_range_empty_range_clears_previous_state(void) { - char *argv1[] = {"program", "--old=1", "oldpos"}; - char *argv2[] = {"program", "command"}; - - tl_parse_args(3, argv1); - TEST_ASSERT_TRUE(tl_lookup_flag("--old")); - TEST_ASSERT_EQUAL_UINT(1, tl_count_positional()); - - TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_parse_args_range(2, argv2, 2, 2, NULL)); - TEST_ASSERT_FALSE(tl_lookup_flag("--old")); - TEST_ASSERT_EQUAL_UINT(0, tl_count_positional()); -} - -static void test_tl_parse_args_range_can_include_argv_zero(void) { - char *argv[] = {"program", "command", "--flag-bool"}; - const char *bool_flags[] = {"--flag-bool", NULL}; - TlParseOptions options = {.bool_flags = bool_flags}; - - TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_parse_args_range(3, argv, 0, 3, &options)); - TEST_ASSERT_EQUAL_STRING("program", tl_get_positional(0)); - TEST_ASSERT_EQUAL_STRING("command", tl_get_positional(1)); - TEST_ASSERT_TRUE(tl_lookup_flag("--flag-bool")); -} - -static void test_tl_parse_args_range_terminator_keeps_positionals(void) { - char *argv[] = {"program", "command", "subcommand", "--", "--unknown", "./tmp/example"}; - const char *bool_flags[] = {"--flag-bool", NULL}; - TlParseOptions options = {.bool_flags = bool_flags}; - - TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_parse_args_range(6, argv, 3, 6, &options)); - TEST_ASSERT_EQUAL_STRING("--unknown", tl_get_positional(0)); - TEST_ASSERT_EQUAL_STRING("./tmp/example", tl_get_positional(1)); -} - -static void test_tl_parse_args_null_argv(void) { - TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_parse_args(0, NULL)); - TEST_ASSERT_EQUAL_UINT(0, tl_count_positional()); - TEST_ASSERT_FALSE(tl_lookup_flag("--anything")); - - TEST_ASSERT_EQUAL_INT(TL_PARSE_OK, tl_parse_args(5, NULL)); - TEST_ASSERT_EQUAL_UINT(0, tl_count_positional()); - TEST_ASSERT_FALSE(tl_lookup_flag("--anything")); -} - -static void test_tl_lookup_positional(void) { - char *argv[] = {"program", "serve", "-f", "file"}; - tl_parse_args(4, argv); - TEST_ASSERT_TRUE(tl_lookup_positional("serve")); - TEST_ASSERT_FALSE(tl_lookup_positional("missing")); -} - -static void test_tl_lookup_positional_multiple(void) { - char *argv[] = {"program", "remote", "add", "origin", "--verbose"}; - tl_parse_args(5, argv); - TEST_ASSERT_TRUE(tl_lookup_positional("remote")); - TEST_ASSERT_TRUE(tl_lookup_positional("add")); - TEST_ASSERT_TRUE(tl_lookup_positional("origin")); - TEST_ASSERT_FALSE(tl_lookup_positional("--verbose")); -} - -static void test_tl_lookup_positional_after_terminator(void) { - char *argv[] = {"program", "cmd", "--", "--foo", "bar"}; - tl_parse_args(5, argv); - TEST_ASSERT_TRUE(tl_lookup_positional("cmd")); - TEST_ASSERT_TRUE(tl_lookup_positional("--foo")); - TEST_ASSERT_TRUE(tl_lookup_positional("bar")); -} - -static void test_tl_lookup_positional_none(void) { - char *argv[] = {"program", "--flag"}; - tl_parse_args(2, argv); - TEST_ASSERT_FALSE(tl_lookup_positional("anything")); -} - -static void test_tl_lookup_positional_null(void) { - char *argv[] = {"program", "cmd"}; - tl_parse_args(2, argv); - TEST_ASSERT_FALSE(tl_lookup_positional(NULL)); -} - -int main(void) { - UNITY_BEGIN(); - - RUN_TEST(test_tl_parse_args); - RUN_TEST(test_tl_lookup_flag); - RUN_TEST(test_tl_get_flag); - RUN_TEST(test_tl_get_flag_space); - RUN_TEST(test_tl_flag_exact_match); - RUN_TEST(test_tl_repeated_flag_equals); - RUN_TEST(test_tl_repeated_flag_mixed); - RUN_TEST(test_tl_repeated_boolean_flag); - RUN_TEST(test_tl_adjacent_space_flags); - RUN_TEST(test_tl_space_flag_trailing_boolean); - RUN_TEST(test_tl_positional_terminator); - RUN_TEST(test_tl_positional_interleaved); - RUN_TEST(test_tl_quoted_value_from_argv); - RUN_TEST(test_tl_parse_line_quoted); - 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_parse_line_null); - 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_arg_index_returns_argv_index); - RUN_TEST(test_tl_arg_index_after_starts_after_given_index); - RUN_TEST(test_tl_arg_index_after_missing_name_returns_not_found); - RUN_TEST(test_tl_flag_public_type_accepts_tl_flag); - RUN_TEST(test_tl_parse_args_ex_null_options_uses_default_parsing); - RUN_TEST(test_tl_parse_args_ex_empty_options_uses_default_parsing); - RUN_TEST(test_tl_parse_args_ex_bool_flag_keeps_positional); - RUN_TEST(test_tl_parse_args_range_bool_before_positional); - RUN_TEST(test_tl_parse_args_range_bool_after_positional); - RUN_TEST(test_tl_parse_args_range_value_flag_space); - RUN_TEST(test_tl_parse_args_range_value_flag_equals); - RUN_TEST(test_tl_parse_args_range_value_flag_without_value_returns_error); - RUN_TEST(test_tl_parse_args_range_dash_value_requires_equals); - RUN_TEST(test_tl_parse_args_range_unknown_flag_returns_error); - RUN_TEST(test_tl_parse_args_range_conflicting_flag_returns_error); - RUN_TEST(test_tl_parse_args_range_invalid_bounds_returns_error); - RUN_TEST(test_tl_parse_args_range_invalid_range_clears_previous_state); - RUN_TEST(test_tl_parse_args_range_empty_range_returns_ok); - RUN_TEST(test_tl_parse_args_range_empty_range_clears_previous_state); - RUN_TEST(test_tl_parse_args_range_can_include_argv_zero); - RUN_TEST(test_tl_parse_args_range_terminator_keeps_positionals); - RUN_TEST(test_tl_parse_args_null_argv); - RUN_TEST(test_tl_lookup_positional); - RUN_TEST(test_tl_lookup_positional_multiple); - RUN_TEST(test_tl_lookup_positional_after_terminator); - RUN_TEST(test_tl_lookup_positional_none); - RUN_TEST(test_tl_lookup_positional_null); - - return UNITY_END(); -}