From e3785dbd08abec09a0edc6ccdf0ebc3b7b71ae09 Mon Sep 17 00:00:00 2001 From: "william.valenduc" Date: Mon, 12 Jan 2026 19:30:11 +0000 Subject: [PATCH] feat(args): args_handler error handling and print_usage --- src/main.c | 15 ++++- src/utils/args/args.c | 33 ++++++++-- src/utils/args/args.h | 7 +++ tests/unit/utils/args.c | 134 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 183 insertions(+), 6 deletions(-) create mode 100644 tests/unit/utils/args.c diff --git a/src/main.c b/src/main.c index f20378e..6ced238 100644 --- a/src/main.c +++ b/src/main.c @@ -1,8 +1,19 @@ // all includes +#include + +#include "utils/args/args.h" + int main(int argc, char **argv) { - (void)argc; - (void)argv; + struct args_options options; + int r = args_handler(argc, argv, &options); + if (r != 0) + { + print_usage(stderr, argv[0]); + return 2; + } + + args_print(&options); return 0; } diff --git a/src/utils/args/args.c b/src/utils/args/args.c index 40b5516..a2dabd8 100644 --- a/src/utils/args/args.c +++ b/src/utils/args/args.c @@ -21,10 +21,19 @@ int args_handler(int argc, char **argv, struct args_options *options) { options->verbose = true; } - else if (strcmp(argv[i], "-c") == 0 && i + 1 < argc) + else if (strcmp(argv[i], "-c") == 0) { if (options->type != INPUT_UNDEFINED) - return 1; // Error: multiple input types specified + { + fprintf(stderr, "Multiple input sources specified: %s\n", + argv[i + 1]); + return 1; + } + else if (i + 1 >= argc) + { + fprintf(stderr, "No command provided after -c\n"); + return 1; + } options->type = INPUT_CMD; options->input_source = argv[i + 1]; @@ -32,12 +41,17 @@ int args_handler(int argc, char **argv, struct args_options *options) } else if (argv[i][0] == '-') { - return 1; // Error: unknown option + fprintf(stderr, "Unknown option: %s\n", argv[i]); + return 1; } else { if (options->type != INPUT_UNDEFINED) - return 1; // Error: multiple input types specified + { + fprintf(stderr, "Multiple input sources specified: %s\n", + argv[i]); + return 1; + } options->type = INPUT_FILE; options->input_source = argv[i]; @@ -62,3 +76,14 @@ void args_print(struct args_options *options) printf("Pretty print: %s\n", options->pretty_print ? "true" : "false"); printf("Verbose: %s\n", options->verbose ? "true" : "false"); } + +void print_usage(FILE *std, const char *program_name) +{ + fprintf(std, "Usage: %s [OPTIONS] [SCRIPT] [ARGUMENTS...]\n", program_name); + fprintf(std, "Options:\n"); + fprintf(std, " -c [SCRIPT] Execute the given command string.\n"); + fprintf(std, " --pretty-print Enable pretty printing of outputs.\n"); + fprintf(std, " --verbose Enable verbose mode.\n"); + fprintf(std, + "If no SCRIPT is provided, input is read from standard input.\n"); +} diff --git a/src/utils/args/args.h b/src/utils/args/args.h index ddb6d8b..d19859b 100644 --- a/src/utils/args/args.h +++ b/src/utils/args/args.h @@ -2,6 +2,7 @@ #define ARGS_H #include +#include enum input_type { @@ -38,4 +39,10 @@ int args_handler(int argc, char **argv, struct args_options *options); */ void args_print(struct args_options *options); +/** Prints the usage information for the program. + * @param std The output stream to print to (e.g., stdout or stderr). + * @param program_name The name of the program. + */ +void print_usage(FILE *std, const char *program_name); + #endif /* ARGS_H */ diff --git a/tests/unit/utils/args.c b/tests/unit/utils/args.c new file mode 100644 index 0000000..04dfe26 --- /dev/null +++ b/tests/unit/utils/args.c @@ -0,0 +1,134 @@ +#include "../../../src/utils/args/args.h" + +#include +#include +#include + +TestSuite(utils_args); + +Test(utils_args, basic_command) +{ + int argc = 3; + struct args_options options; + char *input[] = { "program", "-c", "echo Hello, World!" }; + + int r = args_handler(argc, input, &options); + + cr_expect(r == 0); + cr_expect(options.pretty_print == false); + cr_expect(options.verbose == false); + cr_expect(options.type == INPUT_CMD); + cr_expect(eq(options.input_source, "echo Hello, World!")); +} + +Test(utils_args, basic_command_with_flags) +{ + int argc = 5; + struct args_options options; + char *input[] = { "program", "--pretty-print", "-c", "echo Hello, World!", + "--verbose" }; + + int r = args_handler(argc, input, &options); + + cr_expect(r == 0); + cr_expect(options.pretty_print == true); + cr_expect(options.verbose == true); + cr_expect(options.type == INPUT_CMD); + cr_expect(eq(options.input_source, "echo Hello, World!")); +} + +Test(utils_args, basic_file_input) +{ + int argc = 2; + struct args_options options; + char *input[] = { "program", "input.txt" }; + + int r = args_handler(argc, input, &options); + + cr_expect(r == 0); + cr_expect(options.pretty_print == false); + cr_expect(options.verbose == false); + cr_expect(options.type == INPUT_FILE); + cr_expect(eq(options.input_source, "input.txt")); +} + +Test(utils_args, basic_file_input_with_flags) +{ + int argc = 4; + struct args_options options; + char *input[] = { "program", "--verbose", "input.txt", "--pretty-print" }; + + int r = args_handler(argc, input, &options); + + cr_expect(r == 0); + cr_expect(options.pretty_print == true); + cr_expect(options.verbose == true); + cr_expect(options.type == INPUT_FILE); + cr_expect(eq(options.input_source, "input.txt")); +} + +Test(utils_args, basic_stdin_input) +{ + int argc = 1; + struct args_options options; + char *input[] = { "program" }; + + int r = args_handler(argc, input, &options); + + cr_expect(r == 0); + cr_expect(options.pretty_print == false); + cr_expect(options.verbose == false); + cr_expect(options.type == INPUT_STDIN); + cr_expect(options.input_source == NULL); +} + +Test(utils_args, pretty_print_and_verbose_flags) +{ + int argc = 3; + struct args_options options; + char *input[] = { "program", "--pretty-print", "--verbose" }; + + int r = args_handler(argc, input, &options); + + cr_expect(r == 0); + cr_expect(options.pretty_print == true); + cr_expect(options.verbose == true); + cr_expect(options.type == INPUT_STDIN); + cr_expect(options.input_source == NULL); +} + +Test(utils_args, missing_command_after_c, .init = cr_redirect_stderr) +{ + int argc = 2; + struct args_options options; + char *input[] = { "program", "-c" }; + + int r = args_handler(argc, input, &options); + + cr_expect(r != 0); + cr_assert_stderr_eq_str("No command provided after -c\n"); +} + +Test(utils_args, unknown_option, .init = cr_redirect_stderr) +{ + int argc = 2; + struct args_options options; + char *input[] = { "program", "--unknown" }; + + int r = args_handler(argc, input, &options); + + cr_expect(r != 0); + cr_assert_stderr_eq_str("Unknown option: --unknown\n"); +} + +Test(utils_args, conflicting_input_types, .init = cr_redirect_stderr) +{ + int argc = 4; + struct args_options options; + char *input[] = { "program", "-c", "echo Hello", "input.txt" }; + + int r = args_handler(argc, input, &options); + + cr_expect(r != 0); + cr_assert_stderr_eq_str("Multiple input sources specified: input.txt\n"); +}