diff options
author | Joel Kronqvist <joelkronqvist@proton.me> | 2024-03-24 10:00:19 +0200 |
---|---|---|
committer | Joel Kronqvist <joelkronqvist@proton.me> | 2024-03-24 10:00:19 +0200 |
commit | 1ef526c695df4b37aa184867fb5b62c93118aa02 (patch) | |
tree | e223eda40193d584f55c9f11e8d511988d7e1136 /config-parser.c | |
parent | e26279107edf7012e6b9cd558aaa09a8f0ca4764 (diff) | |
download | stdu-1ef526c695df4b37aa184867fb5b62c93118aa02.tar.gz stdu-1ef526c695df4b37aa184867fb5b62c93118aa02.zip |
Refactored configuration parsing to a separate file and added unit tests to it
Diffstat (limited to 'config-parser.c')
-rw-r--r-- | config-parser.c | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/config-parser.c b/config-parser.c new file mode 100644 index 0000000..cd97dc7 --- /dev/null +++ b/config-parser.c @@ -0,0 +1,226 @@ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <stdbool.h> + +#include "minitest.h" +#include "config-parser.h" + +Result parse_config(int argc, char* argv[]) { + Result res; + res.success = false; + Config tmp; + tmp.precision = 0; + tmp.human_readable = false; + + size_t i = 1; + char* argument; + char* precision = NULL; + while (i < argc) { + argument = argv[i]; + int comp1 = strcmp(argument, "--precision") == 0; + if ( + comp1 || strncmp(argument, "-p", 2) == 0 + ) { + if (precision != NULL) { + char* error_msg = malloc(44); + snprintf( + error_msg, + 44, + "precision can't be specified multiple times" + ); + res.result = error_msg; + return res; + } + i++; + if (strlen(argument) != 2 && !comp1) { + precision = argument + 2; + continue; + } + if (i == argc) { + char* error_msg = malloc(57); + snprintf( + error_msg, + 57, + "`%s` should be followed by an integer argument", + argument + ); + res.result = error_msg; + return res; + } + precision = argv[i]; + } else if ( + strcmp(argument, "--human-readable") == 0 + || strcmp(argument, "-h") == 0 + ) { + if (tmp.human_readable != false) { + char* error_msg = malloc(52); + snprintf( + error_msg, + 52, + "human readability can't be specified multiple times" + ); + res.result = error_msg; + return res; + } + tmp.human_readable = true; + } else { + size_t msg_size = 21 + strlen(argument); + char* error_msg = malloc(msg_size); + snprintf( + error_msg, + msg_size, + "unknown argument: `%s`", + argument + ); + res.result = error_msg; + return res; + } + + i++; + } + + if (precision != NULL) { + char* endptr; + errno = 0; + tmp.precision = (int) strtol(precision, &endptr, 10); + if (errno != 0) { + char* error_msg = malloc(64); + char* errno_str = strerror(errno); + snprintf( + error_msg, + 64, + "invalid precision: %s", + errno_str + ); + free(errno_str); + res.result = error_msg; + return res; + } + if (*endptr != '\0') { + char* error_msg = malloc(53); + snprintf( + error_msg, + 53, + "the precision may not contain non-numeric characters", + precision + ); + res.result = error_msg; + return res; + } + if (tmp.precision <= 0) { + char* error_msg = malloc(50); + snprintf( + error_msg, + 50, + "the precision can't be less than or equal to zero" + ); + res.result = error_msg; + return res; + } + } + + Config* conf = malloc(sizeof(int) + sizeof(bool)); + conf->precision = tmp.precision; + conf->human_readable = tmp.human_readable; + + res.success = true; + res.result = conf; + return res; +} + +char* test_default_config() { + int argc = 1; + char* argv[] = { "stdu" }; + Result res = parse_config(argc, argv); + Config* conf = (Config*) res.result; + mt_assert_eq(res.success, true); + mt_assert_eq(conf->precision, 0); + mt_assert_eq(conf->human_readable, false); + return 0; +} + +char* test_precision_parsing() { + int argc; + Result res; + Config* conf; + char* error_msg; + + argc = 3; + char* argv[] = { "stdu", "--precision", "3" }; + res = parse_config(argc, argv); + conf = (Config*) res.result; + mt_assert_eq(res.success, true); + mt_assert_eq(conf->precision, 3); + mt_assert_eq(conf->human_readable, false); + free(conf); + + argc = 2; + char* argv2[] = { "stdu", "-p" }; + res = parse_config(argc, argv2); + mt_assert( + res.success == false, + "not specifying precision after `-p` didn't error" + ); + free(error_msg); + + argc = 4; + char* argv3[] = { "stdu", "--precision", "1", "-p3" }; + res = parse_config(argc, argv3); + mt_assert( + res.success == false, + "specifying precision multiple times didn't error" + ); + free(res.result); + + return 0; + +} + +char* test_human_readability_parsing() { + int argc; + Result res; + Config* conf; + char* error_msg; + + argc = 2; + char* argv[] = { + "stdu", + "--human-readable" + }; + res = parse_config(argc, argv); + conf = (Config*) res.result; + mt_assert_eq(res.success, true); + mt_assert_eq(conf->precision, 0); + mt_assert_eq(conf->human_readable, true); + free(conf); + + argc = 3; + char* argv3[] = { + "stdu", + "-h", + "-h" + }; + res = parse_config(argc, argv3); + error_msg = (char*) res.result; + mt_assert_eq(res.success, false); + mt_assert( + strcmp( + error_msg, + "human readability can't be specified multiple times" + ), + "should error on double argument of human readability" + ); + free(error_msg); + + return 0; +} + +void parsing_tests() { + mt_run_test(test_default_config); + mt_run_test(test_precision_parsing); + mt_run_test(test_human_readability_parsing); +} |