diff --git a/.github/workflows/cmake-multi-platform.yml b/.github/workflows/cmake-multi-platform.yml index 7ab1b4d..82bf9d6 100644 --- a/.github/workflows/cmake-multi-platform.yml +++ b/.github/workflows/cmake-multi-platform.yml @@ -73,3 +73,11 @@ jobs: # Execute tests defined by the CMake configuration. Note that --build-config is needed because the default Windows generator is a multi-config generator (Visual Studio generator). # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail run: ctest --build-config ${{ matrix.build_type }} + + - name: Upload results to path + uses: actions/upload-artifact@v4 + if: failure() + with: + name: error-log + path: ${{ steps.strings.outputs.build-output-dir }}/Testing/Temporary/LastTest.log + if-no-files-found: ignore diff --git a/argsparse.c b/argsparse.c index 5d7bafe..2be17a5 100644 --- a/argsparse.c +++ b/argsparse.c @@ -18,106 +18,153 @@ #include #include -ARG_DATA_HANDLE argsparse_create(const char* title) +ARG_DATA_HANDLE g_handle = NULL; + +ARG_ERROR argsparse_create(const char* title) { - ARG_DATA_HANDLE p = calloc(1, sizeof(argument_data_t)); - p->title = title; - p->arguments = NULL; - return p; + if (g_handle != NULL) + { + return ERROR_AP_EXISTS; + } + + g_handle = calloc(1, sizeof(argument_data_t)); + if (g_handle) + { + g_handle->title = title; + g_handle->arguments = NULL; + } + return g_handle ? ERROR_AP_NONE : ERROR_AP_MEMORY; } -void argsparse_free(ARG_DATA_HANDLE handle) +void argsparse_free() { - if (handle) + if (g_handle) { - HARGPARSE_ARG_LINKED next = handle->arguments; + HARGPARSE_ARG_LINKED next = g_handle->arguments; while (next) { next = free_linked_argument(next); } - free (handle); + free (g_handle); + g_handle = NULL; } } -char* argsparse_get_shortopts(ARG_DATA_HANDLE handle) +char* argsparse_get_shortopts() { - return (handle) ? handle->shortopts : NULL; + if (CheckHandle()) + exit(ERROR_AP_HANDLE); + + return g_handle->shortopts; } -const char* argsparse_get_title(ARG_DATA_HANDLE handle) +const char* argsparse_get_title() { - return (handle) ? handle->title : NULL; + if (CheckHandle()) + exit(ERROR_AP_HANDLE); + + return g_handle->title; } -ARG_ARGUMENT_HANDLE argsparse_argument_by_name(ARG_DATA_HANDLE handle, const char* name) +ARG_ARGUMENT_HANDLE argsparse_argument_by_name(const char* name) { - return iterate_arguments_return_on_zero(handle, predicate_compare_name, (void*)name); + if (CheckHandle()) + exit(ERROR_AP_HANDLE); + + return iterate_arguments_return_on_zero(g_handle, predicate_compare_name, (void*)name); } -ARG_ARGUMENT_HANDLE argsparse_argument_by_short_name(ARG_DATA_HANDLE handle, int shortname) +ARG_ARGUMENT_HANDLE argsparse_argument_by_short_name(int shortname) { - return iterate_arguments_return_on_zero(handle, predicate_compare_short_name, (void*)&shortname); + if (CheckHandle()) + exit(ERROR_AP_HANDLE); + + return iterate_arguments_return_on_zero(g_handle, predicate_compare_short_name, (void*)&shortname); } -int argsparse_argument_count(ARG_DATA_HANDLE handle) +int argsparse_argument_count() { + if (CheckHandle()) + exit(ERROR_AP_HANDLE); + int ret = 0; - iterate_arguments_return_on_zero(handle, action_count, &ret); + iterate_arguments_return_on_zero(g_handle, action_count, &ret); return ret; } -ARG_ERROR argsparse_add(ARG_DATA_HANDLE handle, const char* name, const char* description, ARG_TYPE type, const ARG_VALUE* value) +ARG_ERROR argsparse_add(const char* name, const char* description, ARG_TYPE type, const ARG_VALUE* value) { + if (CheckHandle()) + exit(ERROR_AP_HANDLE); + ARG_ARGUMENT_HANDLE h = create_argument(type, name, description, value); - return put_argument(handle, &h); + return put_argument(g_handle, &h); } -ARG_ERROR argsparse_add_help(ARG_DATA_HANDLE handle) +ARG_ERROR argsparse_add_help() { + if (CheckHandle()) + exit(ERROR_AP_HANDLE); + ARG_ARGUMENT_HANDLE p = create_argument(ARGSPARSE_TYPE_NONE, "help", "Print this message", NULL); - return put_argument(handle, &p); + return put_argument(g_handle, &p); } -ARG_ERROR argsparse_add_int(ARG_DATA_HANDLE handle, const char* name, const char* description, int value) +ARG_ERROR argsparse_add_int(const char* name, const char* description, int value) { + if (CheckHandle()) + exit(ERROR_AP_HANDLE); + ARG_VALUE argvalue; argvalue.intvalue = value; ARG_ARGUMENT_HANDLE p = create_argument(ARGSPARSE_TYPE_INT, name, description, &argvalue); - return put_argument(handle, &p); + return put_argument(g_handle, &p); } -ARG_ERROR argsparse_add_double(ARG_DATA_HANDLE handle, const char* name, const char* description, double value) +ARG_ERROR argsparse_add_double(const char* name, const char* description, double value) { + if (CheckHandle()) + exit(ERROR_AP_HANDLE); + ARG_VALUE argvalue; argvalue.doublevalue = value; ARG_ARGUMENT_HANDLE p = create_argument(ARGSPARSE_TYPE_DOUBLE, name, description, &argvalue); - return put_argument(handle, &p); + return put_argument(g_handle, &p); } -ARG_ERROR argsparse_add_cstr(ARG_DATA_HANDLE handle, const char* name, const char* description, const char* value) +ARG_ERROR argsparse_add_cstr(const char* name, const char* description, const char* value) { + if (CheckHandle()) + exit(ERROR_AP_HANDLE); + ARG_VALUE argvalue; copy_to_argument_string(argvalue.stringvalue, value); ARG_ARGUMENT_HANDLE p = create_argument(ARGSPARSE_TYPE_STRING, name, description, &argvalue); - return put_argument(handle, &p); + return put_argument(g_handle, &p); } -ARG_ERROR argsparse_add_flag(ARG_DATA_HANDLE handle, const char* name, const char* description, int value, int* ptr_to_value) +ARG_ERROR argsparse_add_flag(const char* name, const char* description, int value, int* ptr_to_value) { + if (CheckHandle()) + exit(ERROR_AP_HANDLE); + ARG_VALUE argvalue = {0, }; argvalue.flagptr = ptr_to_value; ARG_ARGUMENT_HANDLE p = create_argument(ARGSPARSE_TYPE_FLAG, name, description, &argvalue); p->flag_init.flagvalue = value; - return put_argument(handle, &p); + return put_argument(g_handle, &p); } -int argsparse_parse_args(ARG_DATA_HANDLE handle, char* const *argv, int argc) +int argsparse_parse_args(char* const *argv, int argc) { + if (CheckHandle()) + exit(ERROR_AP_HANDLE); + int count = 0; // Although application call this function only once, // tests call this function many times and optind has to be reset. @@ -125,19 +172,19 @@ int argsparse_parse_args(ARG_DATA_HANDLE handle, char* const *argv, int argc) optind = 1; if (argc > 1) { - int arg_count = argsparse_argument_count(handle); + int arg_count = argsparse_argument_count(); struct option *long_options = calloc(arg_count + 1, sizeof(struct option)); if (long_options != NULL) { int c = 0; - iterate_arguments_return_on_zero(handle, action_do_option_long, (void*)(long_options)); + iterate_arguments_return_on_zero(g_handle, action_do_option_long, (void*)(long_options)); while(c != -1) { /* getopt_long stores the option index here (long_options[option_index]). */ int option_index = 0; c = getopt_long(argc, argv, - handle->shortopts, + g_handle->shortopts, (const struct option *)long_options, &option_index); printf("option_index(%d), optind(%d)\n", option_index, optind); @@ -155,16 +202,16 @@ int argsparse_parse_args(ARG_DATA_HANDLE handle, char* const *argv, int argc) break; case 'h': - argsparse_show_usage(handle, argv[0]); + argsparse_show_usage(argv[0]); exit(0); default: printf ("option -%c\n", c); - ARG_ARGUMENT_HANDLE arg = argsparse_argument_by_short_name(handle, c); + ARG_ARGUMENT_HANDLE arg = argsparse_argument_by_short_name(c); if (arg == NULL) { printf ("invalid option -%c\n", c); - argsparse_show_usage(handle, argv[0]); + argsparse_show_usage(argv[0]); exit(1); } else @@ -188,22 +235,25 @@ int argsparse_parse_args(ARG_DATA_HANDLE handle, char* const *argv, int argc) printf("\n"); } - iterate_arguments_return_on_zero(handle, action_mark_parsed_flags, NULL); + iterate_arguments_return_on_zero(g_handle, action_mark_parsed_flags, NULL); free(long_options); } } return count; } -void argsparse_show_usage(ARG_DATA_HANDLE handle, const char* const executable) +void argsparse_show_usage(const char* const executable) { + if (CheckHandle()) + exit(ERROR_AP_HANDLE); + // is there a separator? const char* separator = strrchr(executable, '/') ? strrchr(executable, '/') : strrchr(executable, '\\'); // advance or fallback to executable const char* basename = separator ? separator + 1 : executable; printf("usage: %s", basename); - char* shortopt = handle->shortopts; + char* shortopt = g_handle->shortopts; while (*shortopt) { char c = *shortopt; @@ -213,25 +263,38 @@ void argsparse_show_usage(ARG_DATA_HANDLE handle, const char* const executable) printf(" [-%c]", c); } - printf("\ntitle: %s\n", handle->title); + printf("\ntitle: %s\n", g_handle->title); printf("optional arguments:\n"); - iterate_arguments_return_on_zero(handle, action_show_argument_usage, NULL); + iterate_arguments_return_on_zero(g_handle, action_show_argument_usage, NULL); } -void argsparse_show_arguments(ARG_DATA_HANDLE handle) +void argsparse_show_arguments() { + if (CheckHandle()) + exit(ERROR_AP_HANDLE); + printf("argument values:\n"); size_t width = 0; - iterate_arguments_return_on_zero(handle, action_long_option_width, &width); - iterate_arguments_return_on_zero(handle, action_show_argument_value, (void*)(uintptr_t)width); + iterate_arguments_return_on_zero(g_handle, action_long_option_width, &width); + iterate_arguments_return_on_zero(g_handle, action_show_argument_value, (void*)(uintptr_t)width); } //////////////////////// // Internal functions // //////////////////////// +static ARG_ERROR CheckHandle() +{ + if (g_handle == NULL) + { + fprintf(stderr, "g_handle not initialized"); + return ERROR_AP_HANDLE; + } + return ERROR_AP_NONE; +} + static ARG_ARGUMENT_HANDLE create_argument(ARG_TYPE type, const char* name, const char* desc, const ARG_VALUE* value) { ARG_ARGUMENT_HANDLE p = calloc(1, sizeof(argsparse_argument_t)); @@ -261,13 +324,13 @@ static ARG_ERROR put_argument(ARG_DATA_HANDLE handle, ARG_ARGUMENT_HANDLE* href) { free_argument(href); } - return ERROR_EXISTS; + return ERROR_AP_EXISTS; } if (handle->count >= ARGSPARSE_MAX_ARGS) { free_argument(href); - return ERROR_MAX_ARGS; + return ERROR_AP_MAX_ARGS; } handle->count++; HARGPARSE_ARG_LINKED new_link = calloc(1, sizeof(t_argparse_argument_linked)); @@ -287,7 +350,7 @@ static ARG_ERROR put_argument(ARG_DATA_HANDLE handle, ARG_ARGUMENT_HANDLE* href) else handle->arguments = new_link; - return ERROR_NONE; + return ERROR_AP_NONE; } static HARGPARSE_ARG_LINKED free_linked_argument(HARGPARSE_ARG_LINKED linked) diff --git a/argsparse.h b/argsparse.h index fb08f92..00d1ff4 100644 --- a/argsparse.h +++ b/argsparse.h @@ -23,10 +23,12 @@ extern "C" #endif typedef enum _argsparse_errors { - ERROR_NONE = 0, - ERROR_UNKNOWN = -1, - ERROR_MAX_ARGS = -2, - ERROR_EXISTS = -3, + ERROR_AP_NONE = 0, + ERROR_AP_UNKNOWN = -1, + ERROR_AP_MAX_ARGS = -2, + ERROR_AP_EXISTS = -3, + ERROR_AP_MEMORY = -4, + ERROR_AP_HANDLE = -5, } e_argsparse_errors; typedef enum _argsparse_type { @@ -72,11 +74,10 @@ typedef enum _argsparse_errors ARG_ERROR; /// @brief Create arguments structure /// @param title /// @return handle -ARG_DATA_HANDLE argsparse_create(const char* title); +ARG_ERROR argsparse_create(const char* title); -/// @brief Allocate arguments structure -/// @param handle -void argsparse_free(ARG_DATA_HANDLE handle); +/// @brief Free arguments structure +void argsparse_free(); /// @brief Adds argument using the structured format /// @param handle @@ -85,24 +86,24 @@ void argsparse_free(ARG_DATA_HANDLE handle); /// @param type /// @param value /// @return -/// ERROR_NONE(0) - success +/// ERROR_AP_NONE(0) - success /// -/// ERROR_EXISTS - argument with same name already exists +/// ERROR_AP_EXISTS - argument with same name already exists /// -/// ERROR_MAX_ARGS(1) - ARGSPARSE_MAX_ARGS reached, not added +/// ERROR_AP_MAX_ARGS(1) - ARGSPARSE_MAX_ARGS reached, not added /// @note Smells like internal, but having invested /// a quite a lot to testing it decided to drag it along. -ARG_ERROR argsparse_add(ARG_DATA_HANDLE handle, const char* name, const char* description, ARG_TYPE type, const ARG_VALUE* value); +ARG_ERROR argsparse_add(const char* name, const char* description, ARG_TYPE type, const ARG_VALUE* value); /// @brief Add help option showing usage with exit /// @param handle allocated arguments structure handle /// @return -/// ERROR_NONE(0) - success +/// ERROR_AP_NONE(0) - success /// -/// ERROR_EXISTS - argument with same name already exists +/// ERROR_AP_EXISTS - argument with same name already exists /// -/// ERROR_MAX_ARGS(1) - ARGSPARSE_MAX_ARGS reached, not added -ARG_ERROR argsparse_add_help(ARG_DATA_HANDLE handle); +/// ERROR_AP_MAX_ARGS(1) - ARGSPARSE_MAX_ARGS reached, not added +ARG_ERROR argsparse_add_help(); /// @brief Add int argument /// @param handle allocated arguments structure handle @@ -110,12 +111,12 @@ ARG_ERROR argsparse_add_help(ARG_DATA_HANDLE handle); /// @param desc argument description /// @param value argument value (default) /// @return -/// ERROR_NONE(0) - success +/// ERROR_AP_NONE(0) - success /// -/// ERROR_EXISTS - argument with same name already exists +/// ERROR_AP_EXISTS - argument with same name already exists /// -/// ERROR_MAX_ARGS(1) - ARGSPARSE_MAX_ARGS reached, not added -ARG_ERROR argsparse_add_int(ARG_DATA_HANDLE handle, const char* name, const char* desc, int value); +/// ERROR_AP_MAX_ARGS(1) - ARGSPARSE_MAX_ARGS reached, not added +ARG_ERROR argsparse_add_int(const char* name, const char* desc, int value); /// @brief Add DOUBLE argument /// @param handle allocated arguments structure handle @@ -123,12 +124,12 @@ ARG_ERROR argsparse_add_int(ARG_DATA_HANDLE handle, const char* name, const char /// @param description argument description /// @param value argument value (default) /// @return -/// ERROR_NONE(0) - success +/// ERROR_AP_NONE(0) - success /// -/// ERROR_EXISTS - argument with same name already exists +/// ERROR_AP_EXISTS - argument with same name already exists /// -/// ERROR_MAX_ARGS(1) - ARGSPARSE_MAX_ARGS reached, not added -ARG_ERROR argsparse_add_double(ARG_DATA_HANDLE handle, const char* name, const char* description, double value); +/// ERROR_AP_MAX_ARGS(1) - ARGSPARSE_MAX_ARGS reached, not added +ARG_ERROR argsparse_add_double(const char* name, const char* description, double value); /// @brief Add string argument /// @param handle allocated arguments structure handle @@ -136,12 +137,12 @@ ARG_ERROR argsparse_add_double(ARG_DATA_HANDLE handle, const char* name, const c /// @param description argument description /// @param value argument value (default) /// @return -/// ERROR_NONE(0) - success +/// ERROR_AP_NONE(0) - success /// -/// ERROR_EXISTS - argument with same name already exists +/// ERROR_AP_EXISTS - argument with same name already exists /// -/// ERROR_MAX_ARGS(1) - ARGSPARSE_MAX_ARGS reached, not added -ARG_ERROR argsparse_add_cstr(ARG_DATA_HANDLE handle, const char* name, const char* description, const char* value); +/// ERROR_AP_MAX_ARGS(1) - ARGSPARSE_MAX_ARGS reached, not added +ARG_ERROR argsparse_add_cstr(const char* name, const char* description, const char* value); /// @brief Add argument flag only /// @param handle allocated arguments structure handle @@ -150,53 +151,53 @@ ARG_ERROR argsparse_add_cstr(ARG_DATA_HANDLE handle, const char* name, const cha /// @param value Value to set when option present /// @param ptr_to_value pointer to value or null /// @return -/// ERROR_NONE(0) - success +/// ERROR_AP_NONE(0) - success /// -/// ERROR_EXISTS - argument with same name already exists +/// ERROR_AP_EXISTS - argument with same name already exists /// -/// ERROR_MAX_ARGS(1) - ARGSPARSE_MAX_ARGS reached, not added -ARG_ERROR argsparse_add_flag(ARG_DATA_HANDLE handle, const char* name, const char* description, int value, int* ptr_to_value); +/// ERROR_AP_MAX_ARGS(1) - ARGSPARSE_MAX_ARGS reached, not added +ARG_ERROR argsparse_add_flag(const char* name, const char* description, int value, int* ptr_to_value); /// @brief Parse cmdline argument against added arguments /// @param handle Handle to allocated arguments structure /// @param argsv /// @param argc -int argsparse_parse_args(ARG_DATA_HANDLE handle, char* const* argv, int argc); +int argsparse_parse_args(char* const* argv, int argc); /// @brief Prints usage message /// @param handle -void argsparse_show_usage(ARG_DATA_HANDLE handle, const char* const executable); +void argsparse_show_usage(const char* const executable); /// @brief Prints argument values /// @param handle -void argsparse_show_arguments(ARG_DATA_HANDLE handle); +void argsparse_show_arguments(); /// @brief Get title /// @param handle /// @return string -const char* argsparse_get_title(ARG_DATA_HANDLE handle); +const char* argsparse_get_title(); /// @brief Get short options /// @param handle /// @return -char* argsparse_get_shortopts(ARG_DATA_HANDLE handle); +char* argsparse_get_shortopts(); /// @brief Get argument by name /// @param handle /// @param name /// @return handle to argument -ARG_ARGUMENT_HANDLE argsparse_argument_by_name(ARG_DATA_HANDLE handle, const char* name); +ARG_ARGUMENT_HANDLE argsparse_argument_by_name(const char* name); /// @brief Get argument by short name /// @param handle /// @param name /// @return handle to argument -ARG_ARGUMENT_HANDLE argsparse_argument_by_short_name(ARG_DATA_HANDLE handle, int shortname); +ARG_ARGUMENT_HANDLE argsparse_argument_by_short_name(int shortname); /// @brief Get argument count /// @param handle /// @return count -int argsparse_argument_count(ARG_DATA_HANDLE handle); +int argsparse_argument_count(); #if defined( __cplusplus ) } diff --git a/example/example.cpp b/example/example.cpp index c00ce34..edc7e05 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -6,48 +6,48 @@ int gFlag = 0; int err_print(int err, const char *message); -void initialize_arguments(ARG_DATA_HANDLE arguments); +void initialize_arguments(); void arg_print(ARG_ARGUMENT_HANDLE arg); int main(int argc, char **argv) { - ARG_DATA_HANDLE arguments = argsparse_create("argsparse-example"); + argsparse_create("argsparse-example"); try { - initialize_arguments(arguments); - int parsed = argsparse_parse_args(arguments, argv, argc); - printf("shortopts %s - %d arguments parsed\n", argsparse_get_shortopts(arguments), parsed); - argsparse_show_arguments(arguments); + initialize_arguments(); + int parsed = argsparse_parse_args(argv, argc); + printf("shortopts %s - %d arguments parsed\n", argsparse_get_shortopts(), parsed); + argsparse_show_arguments(); } catch (...) { printf("exit due to exception"); } - argsparse_free(arguments); + argsparse_free(); } -void initialize_arguments(ARG_DATA_HANDLE arguments) +void initialize_arguments() { - ARG_ERROR err = ERROR_NONE; - err = argsparse_add_help(arguments); + ARG_ERROR err = ERROR_AP_NONE; + err = argsparse_add_help(); err_print(err, "help not added"); - err = argsparse_add_int(arguments, "integer", "This is an integer value", 0); + err = argsparse_add_int("integer", "This is an integer value", 0); err_print(err, "integer not added"); - err = argsparse_add_double(arguments, "double", "This is a double value", 0.0); + err = argsparse_add_double("double", "This is a double value", 0.0); err_print(err, "double not added"); - err = argsparse_add_cstr(arguments, "string", "This is a string value", ""); + err = argsparse_add_cstr("string", "This is a string value", ""); err_print(err, "string not added"); - err = argsparse_add_flag(arguments, "flag", "This is a flag value", 123, &gFlag); + err = argsparse_add_flag("flag", "This is a flag value", 123, &gFlag); err_print(err, "flag not added"); } int err_print(int err, const char* message) { - if (err != ERROR_NONE) + if (err != ERROR_AP_NONE) { printf("ERR(%d): %s\n", err, message); throw err; diff --git a/internal_funcs.c b/internal_funcs.c index 8a9bc8e..ef60d82 100644 --- a/internal_funcs.c +++ b/internal_funcs.c @@ -116,7 +116,7 @@ int parse_value(ARG_VALUE* ref, ARG_TYPE type, const char* str_value) int set_short_option(char c, ARG_DATA_HANDLE handle, ARG_ARGUMENT_HANDLE arg) { - int ret = ERROR_EXISTS; + int ret = ERROR_AP_EXISTS; char* opt = handle->shortopts; // iterate used until terminating 0 while (*opt) @@ -141,7 +141,7 @@ int set_short_option(char c, ARG_DATA_HANDLE handle, ARG_ARGUMENT_HANDLE arg) *(opt + 2) = '\0'; } arg->name_short = c; - ret = ERROR_NONE; + ret = ERROR_AP_NONE; } return ret; diff --git a/internal_funcs.h b/internal_funcs.h index a1e03a7..31d1d66 100644 --- a/internal_funcs.h +++ b/internal_funcs.h @@ -5,6 +5,7 @@ #include +static ARG_ERROR CheckHandle(); static ARG_ARGUMENT_HANDLE create_argument(ARG_TYPE type, const char* name, const char* description, const ARG_VALUE* value); static void free_argument(ARG_ARGUMENT_HANDLE* handle); static HARGPARSE_ARG_LINKED free_linked_argument(HARGPARSE_ARG_LINKED arg); @@ -13,11 +14,11 @@ static HARGPARSE_ARG_LINKED free_linked_argument(HARGPARSE_ARG_LINKED arg); /// @param handle Handle to allocated arguments structure /// @param argument Handle to allocated argument /// @return -/// ERROR_NONE(0) - success +/// ERROR_AP_NONE(0) - success /// -/// ERROR_EXISTS - argument with same name already exists +/// ERROR_AP_EXISTS - argument with same name already exists /// -/// ERROR_MAX_ARGS(1) - ARGSPARSE_MAX_ARGS reached, not added +/// ERROR_AP_MAX_ARGS(1) - ARGSPARSE_MAX_ARGS reached, not added static ARG_ERROR put_argument(ARG_DATA_HANDLE handle, ARG_ARGUMENT_HANDLE* argument); void copy_to_argument_string(char* dest, const char* source); diff --git a/test/argsparseTests.cpp b/test/argsparseTests.cpp index 38c80dd..3a82bc9 100644 --- a/test/argsparseTests.cpp +++ b/test/argsparseTests.cpp @@ -17,6 +17,12 @@ #include #include +#if defined(__linux__) +#define ExitCode(a) ((a) < 0 ? (a) + 256 : (a)) +#else +#define ExitCode(a) a +#endif + namespace argsparse::testing { #define TEST_FIXTURE argsparse_test @@ -86,8 +92,7 @@ class TEST_FIXTURE:public ::testing::TestWithParam void TearDown() override { - argsparse_free(gHandle); - gHandle = nullptr; + argsparse_free(); } }; @@ -99,39 +104,68 @@ void print_arguments(char* const* argv, int argc) } } -TEST_F(TEST_FIXTURE, ShouldAllocateHandle) +void assert_create_arguments(const char* title = nullptr, ARG_ERROR expected = ERROR_AP_NONE) +{ + ARG_ERROR err = argsparse_create(title); + ASSERT_THAT(expected, err); +} + +TEST_F(TEST_FIXTURE, Create) +{ + assert_create_arguments(); +} + +TEST_F(TEST_FIXTURE, ErrorWhenDoubleCreate) +{ + assert_create_arguments(); + assert_create_arguments(NULL, ERROR_AP_EXISTS); +} + +TEST_F(TEST_FIXTURE, ExitWhenNoHandle) { - gHandle = argsparse_create(NULL); - ASSERT_THAT(gHandle, NotNull()); + std::cerr << "ExitCode: " << ExitCode(ERROR_AP_HANDLE) << std::endl; + ASSERT_EXIT(argsparse_get_title(), ::testing::ExitedWithCode(ExitCode(ERROR_AP_HANDLE)), "g_handle not initialized"); + ASSERT_EXIT(argsparse_add("", "", ARGSPARSE_TYPE_NONE, NULL), ::testing::ExitedWithCode(ExitCode(ERROR_AP_HANDLE)), "g_handle not initialized"); + ASSERT_EXIT(argsparse_add_cstr("", "", ""), ::testing::ExitedWithCode(ExitCode(ERROR_AP_HANDLE)), "g_handle not initialized"); + ASSERT_EXIT(argsparse_add_int("", "", 1), ::testing::ExitedWithCode(ExitCode(ERROR_AP_HANDLE)), "g_handle not initialized"); + ASSERT_EXIT(argsparse_add_double("", "", 123.1), ::testing::ExitedWithCode(ExitCode(ERROR_AP_HANDLE)), "g_handle not initialized"); + ASSERT_EXIT(argsparse_add_flag("", "", 123, nullptr), ::testing::ExitedWithCode(ExitCode(ERROR_AP_HANDLE)), "g_handle not initialized"); + ASSERT_EXIT(argsparse_argument_by_name(""), ::testing::ExitedWithCode(ExitCode(ERROR_AP_HANDLE)), "g_handle not initialized"); + ASSERT_EXIT(argsparse_argument_by_short_name(1), ::testing::ExitedWithCode(ExitCode(ERROR_AP_HANDLE)), "g_handle not initialized"); + ASSERT_EXIT(argsparse_argument_count(), ::testing::ExitedWithCode(ExitCode(ERROR_AP_HANDLE)), "g_handle not initialized"); + ASSERT_EXIT(argsparse_get_shortopts(), ::testing::ExitedWithCode(ExitCode(ERROR_AP_HANDLE)), "g_handle not initialized"); + ASSERT_EXIT(argsparse_parse_args(nullptr, 0), ::testing::ExitedWithCode(ExitCode(ERROR_AP_HANDLE)), "g_handle not initialized"); + ASSERT_EXIT(argsparse_show_arguments(), ::testing::ExitedWithCode(ExitCode(ERROR_AP_HANDLE)), "g_handle not initialized"); + ASSERT_EXIT(argsparse_show_usage(""), ::testing::ExitedWithCode(ExitCode(ERROR_AP_HANDLE)), "g_handle not initialized"); } TEST_F(TEST_FIXTURE, HandleShouldGetTitle) { const char* title = "Testing version 1.0 - Arguments"; - gHandle = argsparse_create(title); - ASSERT_STREQ(title, argsparse_get_title(gHandle)); + assert_create_arguments(title); + ASSERT_STREQ(title, argsparse_get_title()); } TEST_F(TEST_FIXTURE, ShouldAppendShortOptions) { - gHandle = argsparse_create(NULL); - char* shortopts = argsparse_get_shortopts(gHandle); + assert_create_arguments(); + char* shortopts = argsparse_get_shortopts(); ASSERT_EQ(0, *shortopts); - ASSERT_EQ(ERROR_NONE, argsparse_add_int(gHandle, "integer", "description", 0)); + ASSERT_EQ(ERROR_AP_NONE, argsparse_add_int("integer", "description", 0)); ASSERT_STREQ("i:", shortopts); - ASSERT_EQ(ERROR_NONE, argsparse_add_cstr(gHandle, "string", "description", "value")); + ASSERT_EQ(ERROR_AP_NONE, argsparse_add_cstr("string", "description", "value")); ASSERT_STREQ("i:s:", shortopts); } TEST_F(TEST_FIXTURE, ShouldNotAppendSameOption) { - gHandle = argsparse_create(NULL); - char* shortopts = argsparse_get_shortopts(gHandle); + assert_create_arguments(); + char* shortopts = argsparse_get_shortopts(); ASSERT_EQ(0, *shortopts); - ASSERT_EQ(ERROR_NONE, argsparse_add_int(gHandle, "integer", "description", 0)); - ASSERT_EQ(ERROR_EXISTS, argsparse_add_int(gHandle, "integer", "description", 0)); + ASSERT_EQ(ERROR_AP_NONE, argsparse_add_int("integer", "description", 0)); + ASSERT_EQ(ERROR_AP_EXISTS, argsparse_add_int("integer", "description", 0)); ASSERT_STREQ("i:", shortopts); } @@ -143,23 +177,23 @@ TEST_F(TEST_FIXTURE, ParsesAllOptionTypes) int flgExpected = 1234; int intExpected = 4321; - gHandle = argsparse_create(NULL); - argsparse_add_cstr(gHandle, "string", "", "This is the initial value"); - argsparse_add_double(gHandle, "double", "", 1234.1234); - argsparse_add_flag(gHandle, "flag", "", flgExpected, &flgValue); - argsparse_add_int(gHandle, "integer", "", 1234); + assert_create_arguments(); + argsparse_add_cstr("string", "", "This is the initial value"); + argsparse_add_double("double", "", 1234.1234); + argsparse_add_flag("flag", "", flgExpected, &flgValue); + argsparse_add_int("integer", "", 1234); const char* fmt = "prg --string %s --double %f --flag --integer %d"; sprintf(gBuffer, fmt, strExpected, dblExpected, intExpected); tokenise_to_argc_argv(gBuffer, &gArgc, gArgv, ARGV_SIZE, print_arguments); - ASSERT_EQ(4, argsparse_parse_args(gHandle, gArgv, gArgc)); + ASSERT_EQ(4, argsparse_parse_args(gArgv, gArgc)); ARG_ARGUMENT_HANDLE arg; - arg = argsparse_argument_by_name(gHandle, "string"); + arg = argsparse_argument_by_name("string"); ASSERT_STREQ("new_value", arg->value.stringvalue); - arg = argsparse_argument_by_name(gHandle, "double"); + arg = argsparse_argument_by_name("double"); ASSERT_DOUBLE_EQ(dblExpected, arg->value.doublevalue); ASSERT_EQ(flgExpected, flgValue); - arg = argsparse_argument_by_name(gHandle, "integer"); + arg = argsparse_argument_by_name("integer"); ASSERT_EQ(intExpected, arg->value.intvalue); } @@ -171,12 +205,12 @@ TEST_F(TEST_FIXTURE, ShouldParseOptionLongFlag) sprintf(gBuffer, "program --flag"); tokenise_to_argc_argv(gBuffer, &argc, gArgv, ARGV_SIZE, print_arguments); - gHandle = argsparse_create(NULL); - argsparse_add_flag(gHandle, "flag", "This is a flag", expected, &value); + assert_create_arguments(); + argsparse_add_flag("flag", "This is a flag", expected, &value); - ASSERT_EQ(1, argsparse_parse_args(gHandle, gArgv, argc)); + ASSERT_EQ(1, argsparse_parse_args(gArgv, argc)); - ARG_ARGUMENT_HANDLE arg = argsparse_argument_by_name(gHandle, "flag"); + ARG_ARGUMENT_HANDLE arg = argsparse_argument_by_name("flag"); ASSERT_EQ(1, arg->parsed); ASSERT_EQ(expected, *arg->value.flagptr); } @@ -187,12 +221,12 @@ TEST_F(TEST_FIXTURE, ShouldParseOptionLongInt) sprintf(gBuffer, "program --integer 4321"); tokenise_to_argc_argv(gBuffer, &argc, gArgv, ARGV_SIZE, print_arguments); - gHandle = argsparse_create(NULL); - argsparse_add_int(gHandle, "integer", "This is an integer", 1234); - ARG_ARGUMENT_HANDLE arg = argsparse_argument_by_name(gHandle, "integer"); + assert_create_arguments(); + argsparse_add_int("integer", "This is an integer", 1234); + ARG_ARGUMENT_HANDLE arg = argsparse_argument_by_name("integer"); ASSERT_THAT(arg, NotNull()); ASSERT_EQ(1234, arg->value.intvalue); - ASSERT_EQ(1, argsparse_parse_args(gHandle, gArgv, argc)); + ASSERT_EQ(1, argsparse_parse_args(gArgv, argc)); ASSERT_EQ(1, arg->parsed); ASSERT_EQ(4321, arg->value.intvalue); } @@ -203,12 +237,12 @@ TEST_F(TEST_FIXTURE, ShouldParseOptionLongInt2) sprintf(gBuffer, "program --integer=4321"); tokenise_to_argc_argv(gBuffer, &argc, gArgv, ARGV_SIZE, print_arguments); - gHandle = argsparse_create(NULL); - argsparse_add_int(gHandle, "integer", "This is an integer", 1234); - ARG_ARGUMENT_HANDLE arg = argsparse_argument_by_name(gHandle, "integer"); + assert_create_arguments(); + argsparse_add_int("integer", "This is an integer", 1234); + ARG_ARGUMENT_HANDLE arg = argsparse_argument_by_name("integer"); ASSERT_THAT(arg, NotNull()); ASSERT_EQ(1234, arg->value.intvalue); - ASSERT_EQ(1, argsparse_parse_args(gHandle, gArgv, argc)); + ASSERT_EQ(1, argsparse_parse_args(gArgv, argc)); ASSERT_EQ(1, arg->parsed); ASSERT_EQ(4321, arg->value.intvalue); } @@ -219,12 +253,12 @@ TEST_F(TEST_FIXTURE, ShouldParseOptionShortInt) sprintf(gBuffer, "program -i 4321"); tokenise_to_argc_argv(gBuffer, &argc, gArgv, ARGV_SIZE, print_arguments); - gHandle = argsparse_create(NULL); - argsparse_add_int(gHandle, "integer", "This is an integer", 1234); - ARG_ARGUMENT_HANDLE arg = argsparse_argument_by_name(gHandle, "integer"); + assert_create_arguments(); + argsparse_add_int("integer", "This is an integer", 1234); + ARG_ARGUMENT_HANDLE arg = argsparse_argument_by_name("integer"); ASSERT_THAT(arg, NotNull()); ASSERT_EQ(1234, arg->value.intvalue); - ASSERT_EQ(1, argsparse_parse_args(gHandle, gArgv, argc)); + ASSERT_EQ(1, argsparse_parse_args(gArgv, argc)); ASSERT_EQ(1, arg->parsed); ASSERT_EQ(4321, arg->value.intvalue); } @@ -235,12 +269,12 @@ TEST_F(TEST_FIXTURE, ShouldParseOptionShortDouble) sprintf(gBuffer, "program -d 4321.1234"); tokenise_to_argc_argv(gBuffer, &argc, gArgv, ARGV_SIZE, print_arguments); - gHandle = argsparse_create(NULL); - argsparse_add_double(gHandle, "double", "This is a double", 1234.4321); - ARG_ARGUMENT_HANDLE arg = argsparse_argument_by_name(gHandle, "double"); + assert_create_arguments(); + argsparse_add_double("double", "This is a double", 1234.4321); + ARG_ARGUMENT_HANDLE arg = argsparse_argument_by_name("double"); ASSERT_THAT(arg, NotNull()); ASSERT_EQ(1234.4321, arg->value.doublevalue); - ASSERT_EQ(1, argsparse_parse_args(gHandle, gArgv, argc)); + ASSERT_EQ(1, argsparse_parse_args(gArgv, argc)); ASSERT_EQ(1, arg->parsed); ASSERT_EQ(4321.1234, arg->value.doublevalue); } @@ -251,12 +285,12 @@ TEST_F(TEST_FIXTURE, ShouldParseOptionLongDouble1) sprintf(gBuffer, "program --double 4321.1234"); tokenise_to_argc_argv(gBuffer, &argc, gArgv, ARGV_SIZE, print_arguments); - gHandle = argsparse_create(NULL); - argsparse_add_double(gHandle, "double", "This is a double", 1234.4321); - ARG_ARGUMENT_HANDLE arg = argsparse_argument_by_name(gHandle, "double"); + assert_create_arguments(); + argsparse_add_double("double", "This is a double", 1234.4321); + ARG_ARGUMENT_HANDLE arg = argsparse_argument_by_name("double"); ASSERT_THAT(arg, NotNull()); ASSERT_EQ(1234.4321, arg->value.doublevalue); - ASSERT_EQ(1, argsparse_parse_args(gHandle, gArgv, argc)); + ASSERT_EQ(1, argsparse_parse_args(gArgv, argc)); ASSERT_EQ(1, arg->parsed); ASSERT_EQ(4321.1234, arg->value.doublevalue); } @@ -267,12 +301,12 @@ TEST_F(TEST_FIXTURE, ShouldParseOptionLongDouble2) sprintf(gBuffer, "program --double=4321.1234"); tokenise_to_argc_argv(gBuffer, &argc, gArgv, ARGV_SIZE, print_arguments); - gHandle = argsparse_create(NULL); - argsparse_add_double(gHandle, "double", "This is a double", 1234.4321); - ARG_ARGUMENT_HANDLE arg = argsparse_argument_by_name(gHandle, "double"); + assert_create_arguments(); + argsparse_add_double("double", "This is a double", 1234.4321); + ARG_ARGUMENT_HANDLE arg = argsparse_argument_by_name("double"); ASSERT_THAT(arg, NotNull()); ASSERT_EQ(1234.4321, arg->value.doublevalue); - ASSERT_EQ(1, argsparse_parse_args(gHandle, gArgv, argc)); + ASSERT_EQ(1, argsparse_parse_args(gArgv, argc)); ASSERT_EQ(1, arg->parsed); ASSERT_EQ(4321.1234, arg->value.doublevalue); } @@ -285,12 +319,12 @@ TEST_F(TEST_FIXTURE, ShouldParseOptionShortString) sprintf(gBuffer, "%s%s", "program -s ", expvalue); tokenise_to_argc_argv(gBuffer, &argc, gArgv, ARGV_SIZE, print_arguments); - gHandle = argsparse_create(NULL); - argsparse_add_cstr(gHandle, "string", "This is a string", defvalue); - ARG_ARGUMENT_HANDLE arg = argsparse_argument_by_name(gHandle, "string"); + assert_create_arguments(); + argsparse_add_cstr("string", "This is a string", defvalue); + ARG_ARGUMENT_HANDLE arg = argsparse_argument_by_name("string"); ASSERT_THAT(arg, NotNull()); ASSERT_EQ(0, strncmp(defvalue, arg->value.stringvalue, strlen(defvalue))); - ASSERT_EQ(1, argsparse_parse_args(gHandle, gArgv, argc)); + ASSERT_EQ(1, argsparse_parse_args(gArgv, argc)); ASSERT_EQ(1, arg->parsed); ASSERT_STREQ(expvalue, arg->value.stringvalue); } @@ -303,12 +337,12 @@ TEST_F(TEST_FIXTURE, ShouldParseOptionLongString1) sprintf(gBuffer, "%s%s", "program --string=", expvalue); tokenise_to_argc_argv(gBuffer, &argc, gArgv, ARGV_SIZE, print_arguments); - gHandle = argsparse_create(NULL); - argsparse_add_cstr(gHandle, "string", "This is a string", defvalue); - ARG_ARGUMENT_HANDLE arg = argsparse_argument_by_name(gHandle, "string"); + assert_create_arguments(); + argsparse_add_cstr("string", "This is a string", defvalue); + ARG_ARGUMENT_HANDLE arg = argsparse_argument_by_name("string"); ASSERT_THAT(arg, NotNull()); ASSERT_EQ(0, strncmp(defvalue, arg->value.stringvalue, strlen(defvalue))); - ASSERT_EQ(1, argsparse_parse_args(gHandle, gArgv, argc)); + ASSERT_EQ(1, argsparse_parse_args(gArgv, argc)); ASSERT_EQ(1, arg->parsed); ASSERT_STREQ(expvalue, arg->value.stringvalue); } @@ -321,12 +355,12 @@ TEST_F(TEST_FIXTURE, ShouldParseOptionLongString2) sprintf(gBuffer, "%s%s", "program --string ", "4321.1234"); tokenise_to_argc_argv(gBuffer, &argc, gArgv, ARGV_SIZE, print_arguments); - gHandle = argsparse_create(NULL); - argsparse_add_cstr(gHandle, "string", "This is a string", defvalue); - ARG_ARGUMENT_HANDLE arg = argsparse_argument_by_name(gHandle, "string"); + assert_create_arguments(); + argsparse_add_cstr("string", "This is a string", defvalue); + ARG_ARGUMENT_HANDLE arg = argsparse_argument_by_name("string"); ASSERT_THAT(arg, NotNull()); ASSERT_EQ(0, strncmp(defvalue, arg->value.stringvalue, strlen(defvalue))); - ASSERT_EQ(1, argsparse_parse_args(gHandle, gArgv, argc)); + ASSERT_EQ(1, argsparse_parse_args(gArgv, argc)); ASSERT_EQ(1, arg->parsed); ASSERT_EQ(0, strncmp(expvalue, arg->value.stringvalue, strlen(expvalue))); } @@ -339,12 +373,12 @@ TEST_F(TEST_FIXTURE, SplitsWhitespaceString) sprintf(gBuffer, "%s%s", "program --string ", expvalue); tokenise_to_argc_argv(gBuffer, &argc, gArgv, ARGV_SIZE, print_arguments); - gHandle = argsparse_create(NULL); - argsparse_add_cstr(gHandle, "string", "This is a string", defvalue); - ARG_ARGUMENT_HANDLE arg = argsparse_argument_by_name(gHandle, "string"); + assert_create_arguments(); + argsparse_add_cstr("string", "This is a string", defvalue); + ARG_ARGUMENT_HANDLE arg = argsparse_argument_by_name("string"); ASSERT_THAT(arg, NotNull()); ASSERT_EQ(0, strncmp(defvalue, arg->value.stringvalue, strlen(defvalue))); - ASSERT_EQ(1, argsparse_parse_args(gHandle, gArgv, argc)); + ASSERT_EQ(1, argsparse_parse_args(gArgv, argc)); ASSERT_EQ(1, arg->parsed); ASSERT_STRNE(expvalue, arg->value.stringvalue); // cut the string @@ -366,12 +400,12 @@ TEST_F(TEST_FIXTURE, ShouldParseDoubleQuotedWhitespaceString) argc = 3; print_arguments(gArgv, argc); - gHandle = argsparse_create(NULL); - argsparse_add_cstr(gHandle, "string", "This is a string", defvalue); - ARG_ARGUMENT_HANDLE arg = argsparse_argument_by_name(gHandle, "string"); + assert_create_arguments(); + argsparse_add_cstr("string", "This is a string", defvalue); + ARG_ARGUMENT_HANDLE arg = argsparse_argument_by_name("string"); ASSERT_THAT(arg, NotNull()); ASSERT_EQ(0, strncmp(defvalue, arg->value.stringvalue, strlen(defvalue))); - ASSERT_EQ(1, argsparse_parse_args(gHandle, gArgv, argc)); + ASSERT_EQ(1, argsparse_parse_args(gArgv, argc)); ASSERT_EQ(1, arg->parsed); ASSERT_EQ(0, strncmp(expvalue, arg->value.stringvalue, strlen(expvalue))); } @@ -388,11 +422,11 @@ TEST_F(TEST_FIXTURE, UsageOutput) " args: [str:defvalue]\n" "\n"; - gHandle = argsparse_create("Title"); + assert_create_arguments("Title"); - argsparse_add_cstr(gHandle, "string", "This is a string", "defvalue"); + argsparse_add_cstr("string", "This is a string", "defvalue"); ::testing::internal::CaptureStdout(); - argsparse_show_usage(gHandle, executable); + argsparse_show_usage(executable); std::string output = ::testing::internal::GetCapturedStdout(); ASSERT_STREQ(expected, output.c_str()); } @@ -402,11 +436,11 @@ TEST_F(TEST_FIXTURE, UsageOutput) TEST_P(TEST_FIXTURE, ShouldAddArgument) { TestParams params = GetParam(); - gHandle = argsparse_create(NULL); - ASSERT_EQ(0, argsparse_argument_count(gHandle)); - ASSERT_EQ(ERROR_NONE, argsparse_add(gHandle, "argument", "This is and argument", params.Type, &(params.Value))); - ASSERT_EQ(1, argsparse_argument_count(gHandle)); - ARG_ARGUMENT_HANDLE arg = argsparse_argument_by_name(gHandle, "argument"); + assert_create_arguments(); + ASSERT_EQ(0, argsparse_argument_count()); + ASSERT_EQ(ERROR_AP_NONE, argsparse_add("argument", "This is and argument", params.Type, &(params.Value))); + ASSERT_EQ(1, argsparse_argument_count()); + ARG_ARGUMENT_HANDLE arg = argsparse_argument_by_name("argument"); ARG_VALUE value = arg->value; switch (params.Type) {