From ccd15d4e64848f29d36823ca92ee639057f544b7 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Sun, 22 Jan 2023 20:58:07 -0600 Subject: [PATCH] Bugfix: Short console arguments should not match when a single invalid exists. While convenient, "fake -help" should not print help. This is because there is no short command starting with the letters "e" or "l". This behavior of succeeded is confusing and misleading. Redesign the logic to better handle this. Improve the unit tests to catch more cases, including this one. --- level_0/f_console/c/console.c | 262 ++++++++++----------- level_0/f_console/c/console.h | 2 + .../tests/unit/c/test-console-parameter_process.c | 257 ++++++++++++++++++-- .../tests/unit/c/test-console-parameter_process.h | 7 + level_0/f_console/tests/unit/c/test-console.c | 1 + 5 files changed, 371 insertions(+), 158 deletions(-) diff --git a/level_0/f_console/c/console.c b/level_0/f_console/c/console.c index 52f14f2..5212773 100644 --- a/level_0/f_console/c/console.c +++ b/level_0/f_console/c/console.c @@ -165,30 +165,30 @@ extern "C" { f_status_t status = f_string_dynamics_increase_by(arguments.argc, ¶meters->arguments); if (F_status_is_error(status)) return status; + f_array_lengths_t needs = f_array_lengths_t_initialize; + + status = f_array_lengths_increase(F_memory_default_allocation_small_d, &needs); + if (F_status_is_error(status)) return status; + // Append the program name parameter. parameters->arguments.array[parameters->arguments.used].string = arguments.argv[0]; parameters->arguments.array[parameters->arguments.used].used = strnlen(arguments.argv[0], F_console_parameter_size_d); parameters->arguments.array[parameters->arguments.used++].size = 0; f_console_id_t result = f_console_id_t_initialize; - bool found = F_false; // Parameter 0 represents the program name so skip it. unsigned long location = 1; - f_array_length_t sub_location = 0; - f_array_length_t increment_by = 0; - + f_array_length_t location_sub = 0; f_array_length_t i = 0; - f_array_length_t values = 0; - - uint8_t console_short = f_console_none_e; - uint8_t console_long = f_console_none_e; - uint8_t console_type = f_console_type_normal_e; + f_array_length_t j = 0; - f_array_lengths_t needs_value = f_array_lengths_t_initialize; + f_utf_char_t utf_argument = 0; + f_utf_char_t utf_console = 0; uint8_t width = 0; + bool found = F_false; while (location < arguments.argc && arguments.argv[location]) { @@ -197,191 +197,185 @@ extern "C" { parameters->arguments.array[parameters->arguments.used++].size = 0; // Additional parameters must always follow what requests them. - if (needs_value.used > 0) { - i = needs_value.array[0]; - - status = f_array_lengths_increase(F_memory_default_allocation_small_d, ¶meters->array[i].values); - if (F_status_is_error(status)) break; + if (needs.used) { + i = needs.array[0]; parameters->array[i].result = f_console_result_additional_e; - parameters->array[i].values.array[parameters->array[i].values.used++] = location; + parameters->array[i].values.array[parameters->array[i].values.used++] = location++; - --needs_value.used; + --needs.used; - // Pop the matched parameter off of the top of the needs_value array. - for (i = 0; i < needs_value.used; ++i) { - needs_value.array[i] = needs_value.array[i + 1]; + for (i = 0; i < needs.used; ++i) { + needs.array[i] = needs.array[i + 1]; } // for - ++location; - continue; } private_f_console_identify(arguments.argv[location], &result); - // Process the current parameter. - if (result == f_console_short_enable_e || result == f_console_short_disable_e) { - increment_by = 1; - sub_location = 1; - } - else if (result == f_console_long_enable_e || result == f_console_long_disable_e) { - increment_by = parameters->arguments.array[location].used; - sub_location = 2; - } - else { - increment_by = parameters->arguments.array[location].used; - sub_location = 0; - } - - // Handle the normal commands. - if (result == f_console_short_enable_e || result == f_console_long_enable_e) { - console_short = f_console_short_enable_e; - console_long = f_console_long_enable_e; - console_type = f_console_type_normal_e; - } - else if (result == f_console_short_disable_e || result == f_console_long_disable_e) { - console_short = f_console_short_disable_e; - console_long = f_console_long_disable_e; - console_type = f_console_type_inverse_e; - } - else { - console_short = f_console_none_e; - } - found = F_false; - if (console_short != f_console_none_e) { + if (result == f_console_short_enable_e || result == f_console_short_disable_e) { + + // Perform pre-process. + for (location_sub = 1; location_sub < parameters->arguments.array[location].used; ++location_sub) { - // The sub_location is used on a per increment basis (such as 'tar -xcf', the '-' would have an increment of 1, therefore x, c, and f would all be three separate parameters). - while (sub_location < parameters->arguments.array[location].used) { + found = F_false; for (i = 0; i < parameters->used; ++i) { - if (parameters->array[i].type != console_type) continue; + if (parameters->array[i].type != (result == f_console_short_enable_e ? f_console_type_normal_e : f_console_type_inverse_e)) continue; + if (!parameters->array[i].symbol_short) continue; + if (arguments.argv[location][location_sub] != *parameters->array[i].symbol_short) continue; - if (result == console_short) { - if (!parameters->array[i].symbol_short) continue; + width = macro_f_utf_byte_width_is(arguments.argv[location][location_sub]); - width = macro_f_utf_byte_width_is(arguments.argv[location][sub_location]); + if (width) { + utf_argument = 0; + utf_console = 0; - if (width > 0) { - increment_by = width; - } + status = f_utf_char_to_character(arguments.argv[location] + location_sub, parameters->arguments.array[location].used - location_sub, &utf_argument); + if (F_status_is_error(status)) break; - if (arguments.argv[location][sub_location] != *parameters->array[i].symbol_short) continue; + status = f_utf_char_to_character((f_string_t) parameters->array[i].symbol_short, strlen(parameters->array[i].symbol_short), &utf_console); + if (F_status_is_error(status)) break; - if (width > 0) { - f_utf_char_t character_argument_utf = 0; - f_utf_char_t character_console_utf = 0; + if (utf_argument != utf_console) continue; + } - f_number_unsigned_t width_max = parameters->arguments.array[location].used - sub_location; + found = F_true; - status = f_utf_char_to_character(arguments.argv[location] + sub_location, width_max, &character_argument_utf); - if (F_status_is_error(status)) break; + break; + } // for - width_max = strlen(parameters->array[i].symbol_short); + if (F_status_is_error(status)) break; + if (!found) break; + } // for - status = f_utf_char_to_character((f_string_t) parameters->array[i].symbol_short, width_max, &character_console_utf); - if (F_status_is_error(status)) break; + if (F_status_is_error(status)) break; - if (character_argument_utf != character_console_utf) continue; - } - } - else if (result == console_long) { - if (!parameters->array[i].symbol_long) continue; + // The entire string references valid parameters. + if (found) { + location_sub = 1; + needs.used = 0; - if (strncmp(&arguments.argv[location][sub_location], parameters->array[i].symbol_long, increment_by + 1) != 0) { - continue; - } - } - else { - continue; - } + status = f_array_lengths_increase_by(parameters->arguments.array[location].used, &needs); + if (F_status_is_error(status)) break; - status = f_array_lengths_increase(F_memory_default_allocation_small_d, ¶meters->array[i].locations); - if (F_status_is_error(status)) break; + // The location_sub is used on a per-increment basis (such as 'tar -xcf', the '-' would have an increment of 1, therefore x, c, and f would all be three separate parameters). + while (location_sub < parameters->arguments.array[location].used) { - status = f_array_lengths_increase(F_memory_default_allocation_small_d, ¶meters->array[i].locations_sub); - if (F_status_is_error(status)) break; + width = macro_f_utf_byte_width_is(arguments.argv[location][location_sub]); - found = F_true; + if (width) { + utf_argument = 0; + utf_console = 0; - parameters->array[i].locations.array[parameters->array[i].locations.used++] = location; + status = f_utf_char_to_character(arguments.argv[location] + location_sub, parameters->arguments.array[location].used - location_sub, &utf_argument); + if (F_status_is_error(status)) break; - parameters->array[i].result = f_console_result_found_e; - parameters->array[i].location = location; - parameters->array[i].location_sub = 0; + status = f_utf_char_to_character((f_string_t) parameters->array[i].symbol_short, strlen(parameters->array[i].symbol_short), &utf_console); + if (F_status_is_error(status)) break; - if (result == console_short) { - parameters->array[i].location_sub = sub_location; - parameters->array[i].locations_sub.array[parameters->array[i].locations_sub.used++] = sub_location; + if (utf_argument != utf_console) continue; } else { - parameters->array[i].locations_sub.array[parameters->array[i].locations_sub.used++] = 0; + width = 1; } - if (parameters->array[i].values_total) { - status = f_array_lengths_increase_by(parameters->array[i].values_total, &needs_value); + for (i = 0; i < parameters->used; ++i) { + + if (parameters->array[i].type != (result == f_console_short_enable_e ? f_console_type_normal_e : f_console_type_inverse_e)) continue; + if (!parameters->array[i].symbol_short) continue; + if (arguments.argv[location][location_sub] != *parameters->array[i].symbol_short) continue; + + status = f_array_lengths_increase(F_memory_default_allocation_small_d, ¶meters->array[i].locations); if (F_status_is_error(status)) break; - for (values = 0; values < parameters->array[i].values_total; ++values) { - needs_value.array[needs_value.used++] = i; + status = f_array_lengths_increase(F_memory_default_allocation_small_d, ¶meters->array[i].locations_sub); + if (F_status_is_error(status)) break; + + if (parameters->array[i].location != location) { + parameters->array[i].locations.array[parameters->array[i].locations.used++] = location; + } + + parameters->array[i].result = f_console_result_found_e; + parameters->array[i].location = location; + parameters->array[i].location_sub = location_sub; + parameters->array[i].locations_sub.array[parameters->array[i].locations_sub.used++] = location_sub; + + for (j = 0; j < parameters->array[i].values_total; ++j) { + needs.array[needs.used++] = i; } // for - } - break; - } // for + status = f_array_lengths_increase_by(needs.used, ¶meters->array[i].values); + if (F_status_is_error(status)) break; - if (F_status_is_error(status)) break; + break; + } // for - sub_location += increment_by; - } // while + if (F_status_is_error(status)) break; - if (F_status_is_error(status)) break; + location_sub += width; + } // while + } } else { - for (i = 0; i < parameters->used; ++i) { + if (result == f_console_long_enable_e || result == f_console_long_disable_e) { + location_sub = 2; + needs.used = 0; + + for (i = 0; i < parameters->used; ++i) { + + if (parameters->array[i].type != (result == f_console_long_enable_e ? f_console_type_normal_e : f_console_type_inverse_e)) continue; + if (!parameters->array[i].symbol_long) continue; + if (strncmp(&arguments.argv[location][location_sub], parameters->array[i].symbol_long, parameters->arguments.array[location].used + 1)) continue; + + found = F_true; + + break; + } // for + } + else { + for (i = 0; i < parameters->used; ++i) { - if (parameters->array[i].type != f_console_type_other_e) continue; - if (!parameters->array[i].symbol_other) continue; - if (strncmp(arguments.argv[location], parameters->array[i].symbol_other, parameters->arguments.array[location].used + 1) != 0) continue; + if (parameters->array[i].type != f_console_type_other_e) continue; + if (!parameters->array[i].symbol_other) continue; + if (strncmp(arguments.argv[location], parameters->array[i].symbol_other, parameters->arguments.array[location].used + 1)) continue; + found = F_true; + + break; + } // for + } + + if (found) { status = f_array_lengths_increase(F_memory_default_allocation_small_d, ¶meters->array[i].locations); if (F_status_is_error(status)) break; status = f_array_lengths_increase(F_memory_default_allocation_small_d, ¶meters->array[i].locations_sub); if (F_status_is_error(status)) break; - parameters->array[i].locations.array[parameters->array[i].locations.used++] = location; - parameters->array[i].locations_sub.array[parameters->array[i].locations_sub.used++] = 0; - parameters->array[i].result = f_console_result_found_e; parameters->array[i].location = location; parameters->array[i].location_sub = 0; + parameters->array[i].locations.array[parameters->array[i].locations.used++] = location; + parameters->array[i].locations_sub.array[parameters->array[i].locations_sub.used++] = 0; - if (parameters->array[i].values_total) { - if (needs_value.used + parameters->array[i].values_total > needs_value.size) { - status = f_array_lengths_resize(needs_value.used + parameters->array[i].values_total, &needs_value); - if (F_status_is_error(status)) break; - } - - for (values = 0; values < parameters->array[i].values_total; ++values) { - needs_value.array[needs_value.used++] = i; - } // for - } - - found = F_true; - - break; - } // for + for (j = 0; j < parameters->array[i].values_total; ++j) { + needs.array[needs.used++] = i; + } // for - if (F_status_is_error(status)) break; + status = f_array_lengths_increase_by(needs.used, ¶meters->array[i].values); + if (F_status_is_error(status)) break; + } } - if (!found) { + if (F_status_is_error(status)) break; - // Populate list of remaining parameters->array that are not associated with anything. + // Add the missed parameter to the remaining array. + if (!found) { status = f_array_lengths_increase(F_memory_default_allocation_small_d, ¶meters->remaining); if (F_status_is_error(status)) break; @@ -400,10 +394,10 @@ extern "C" { } // for if (F_status_is_error_not(status)) { - status = needs_value.used ? F_complete_not : F_none; + status = needs.used ? F_complete_not : F_none; } - f_array_lengths_resize(0, &needs_value); + f_array_lengths_resize(0, &needs); return status; } diff --git a/level_0/f_console/c/console.h b/level_0/f_console/c/console.h index 4f6df8b..04319b9 100644 --- a/level_0/f_console/c/console.h +++ b/level_0/f_console/c/console.h @@ -169,10 +169,12 @@ extern "C" { * * Errors (with error bit) from: f_array_lengths_increase(). * Errors (with error bit) from: f_array_lengths_increase_by(). + * Errors (with error bit) from: f_string_dynamics_increase_by(). * Errors (with error bit) from: f_utf_char_to_character(). * * @see f_array_lengths_increase() * @see f_array_lengths_increase_by() + * @see f_string_dynamics_increase_by() * @see f_utf_char_to_character() */ #ifndef _di_f_console_parameter_process_ diff --git a/level_0/f_console/tests/unit/c/test-console-parameter_process.c b/level_0/f_console/tests/unit/c/test-console-parameter_process.c index b43f48e..0f1db02 100644 --- a/level_0/f_console/tests/unit/c/test-console-parameter_process.c +++ b/level_0/f_console/tests/unit/c/test-console-parameter_process.c @@ -5,6 +5,106 @@ extern "C" { #endif +void test__f_console_parameter_process__incomplete_arguments(void **state) { + + const f_string_t argv[] = { + "program", + "--second", + 0, + }; + + const f_console_arguments_t arguments = macro_f_console_arguments_t_initialize(2, argv, 0); + + f_console_parameter_t parameter[] = { + macro_f_console_parameter_t_initialize("f", 0, 0, 1, f_console_type_normal_e), + macro_f_console_parameter_t_initialize("s", "second", 0, 1, f_console_type_normal_e), + macro_f_console_parameter_t_initialize("t", "third", 0, 1, f_console_type_normal_e), + macro_f_console_parameter_t_initialize("F", 0, 0, 0, f_console_type_inverse_e), + macro_f_console_parameter_t_initialize(0, "fifth", 0, 1, f_console_type_inverse_e), + macro_f_console_parameter_t_initialize(0, "sixth", 0, 1, f_console_type_normal_e), + macro_f_console_parameter_t_initialize(0, "seventh", 0, 2, f_console_type_normal_e), + macro_f_console_parameter_t_initialize("N", "not_found", 0, 0, f_console_type_normal_e), + macro_f_console_parameter_t_initialize(0, 0, "other", 0, f_console_type_other_e), + }; + + f_console_parameters_t parameters = macro_f_console_parameters_t_initialize(parameter, 9); + + { + const f_status_t status = f_console_parameter_process(arguments, ¶meters); + + assert_int_equal(status, F_complete_not); + + assert_int_equal(parameter[0].result, f_console_result_none_e); + assert_int_equal(parameter[0].locations.used, 0); + assert_int_equal(parameter[0].locations_sub.used, 0); + assert_int_equal(parameter[0].values.used, 0); + assert_int_equal(parameter[0].location, 0); + assert_int_equal(parameter[0].location_sub, 0); + + assert_int_equal(parameter[1].result, f_console_result_found_e); + assert_int_equal(parameter[1].locations.used, 1); + assert_int_equal(parameter[1].locations_sub.used, 1); + assert_int_equal(parameter[1].values.used, 0); + assert_int_equal(parameter[1].location, 1); + assert_int_equal(parameter[1].location_sub, 0); + assert_int_equal(parameter[1].locations.array[0], 1); + assert_int_equal(parameter[1].locations_sub.array[0], 0); + + assert_int_equal(parameter[2].result, f_console_result_none_e); + assert_int_equal(parameter[2].locations.used, 0); + assert_int_equal(parameter[2].locations_sub.used, 0); + assert_int_equal(parameter[2].values.used, 0); + assert_int_equal(parameter[2].location, 0); + assert_int_equal(parameter[2].location_sub, 0); + + assert_int_equal(parameter[3].result, f_console_result_none_e); + assert_int_equal(parameter[3].locations.used, 0); + assert_int_equal(parameter[3].locations_sub.used, 0); + assert_int_equal(parameter[3].values.used, 0); + assert_int_equal(parameter[3].location, 0); + assert_int_equal(parameter[3].location_sub, 0); + + assert_int_equal(parameter[4].result, f_console_result_none_e); + assert_int_equal(parameter[4].locations.used, 0); + assert_int_equal(parameter[4].locations_sub.used, 0); + assert_int_equal(parameter[4].values.used, 0); + assert_int_equal(parameter[4].location, 0); + assert_int_equal(parameter[4].location_sub, 0); + + assert_int_equal(parameter[5].result, f_console_result_none_e); + assert_int_equal(parameter[5].locations.used, 0); + assert_int_equal(parameter[5].locations_sub.used, 0); + assert_int_equal(parameter[5].values.used, 0); + assert_int_equal(parameter[5].location, 0); + assert_int_equal(parameter[5].location_sub, 0); + + assert_int_equal(parameter[6].result, f_console_result_none_e); + assert_int_equal(parameter[6].locations.used, 0); + assert_int_equal(parameter[6].locations_sub.used, 0); + assert_int_equal(parameter[6].values.used, 0); + assert_int_equal(parameter[6].location, 0); + assert_int_equal(parameter[6].location_sub, 0); + + assert_int_equal(parameter[7].result, f_console_result_none_e); + assert_int_equal(parameter[7].locations.used, 0); + assert_int_equal(parameter[7].locations_sub.used, 0); + assert_int_equal(parameter[7].values.used, 0); + assert_int_equal(parameter[7].location, 0); + assert_int_equal(parameter[7].location_sub, 0); + + assert_int_equal(parameter[8].result, f_console_result_none_e); + assert_int_equal(parameter[8].locations.used, 0); + assert_int_equal(parameter[8].locations_sub.used, 0); + assert_int_equal(parameter[8].values.used, 0); + assert_int_equal(parameter[8].location, 0); + assert_int_equal(parameter[8].location_sub, 0); + + assert_int_equal(parameters.remaining.used, 0); + } + + f_console_parameters_delete(¶meters); +} + void test__f_console_parameter_process__no_arguments_no_program(void **state) { const f_string_t argv[] = { @@ -104,7 +204,7 @@ void test__f_console_parameter_process__no_arguments(void **state) { }; // Test both valid and invalid argc. - for (uint8_t argc = 0; argc < 3; ++argc) { + for (uint8_t argc = 0; argc < 2; ++argc) { const f_console_arguments_t arguments = macro_f_console_arguments_t_initialize(argc, argv, 0); @@ -129,54 +229,63 @@ void test__f_console_parameter_process__no_arguments(void **state) { assert_int_equal(parameter[0].result, f_console_result_none_e); assert_int_equal(parameter[0].locations.used, 0); + assert_int_equal(parameter[0].locations_sub.used, 0); assert_int_equal(parameter[0].values.used, 0); assert_int_equal(parameter[0].location, 0); assert_int_equal(parameter[0].location_sub, 0); assert_int_equal(parameter[1].result, f_console_result_none_e); assert_int_equal(parameter[1].locations.used, 0); + assert_int_equal(parameter[1].locations_sub.used, 0); assert_int_equal(parameter[1].values.used, 0); assert_int_equal(parameter[1].location, 0); assert_int_equal(parameter[1].location_sub, 0); assert_int_equal(parameter[2].result, f_console_result_none_e); assert_int_equal(parameter[2].locations.used, 0); + assert_int_equal(parameter[2].locations_sub.used, 0); assert_int_equal(parameter[2].values.used, 0); assert_int_equal(parameter[2].location, 0); assert_int_equal(parameter[2].location_sub, 0); assert_int_equal(parameter[3].result, f_console_result_none_e); assert_int_equal(parameter[3].locations.used, 0); + assert_int_equal(parameter[3].locations_sub.used, 0); assert_int_equal(parameter[3].values.used, 0); assert_int_equal(parameter[3].location, 0); assert_int_equal(parameter[3].location_sub, 0); assert_int_equal(parameter[4].result, f_console_result_none_e); assert_int_equal(parameter[4].locations.used, 0); + assert_int_equal(parameter[4].locations_sub.used, 0); assert_int_equal(parameter[4].values.used, 0); assert_int_equal(parameter[4].location, 0); assert_int_equal(parameter[4].location_sub, 0); assert_int_equal(parameter[5].result, f_console_result_none_e); assert_int_equal(parameter[5].locations.used, 0); + assert_int_equal(parameter[5].locations_sub.used, 0); assert_int_equal(parameter[5].values.used, 0); assert_int_equal(parameter[5].location, 0); assert_int_equal(parameter[5].location_sub, 0); assert_int_equal(parameter[6].result, f_console_result_none_e); assert_int_equal(parameter[6].locations.used, 0); + assert_int_equal(parameter[6].locations_sub.used, 0); assert_int_equal(parameter[6].values.used, 0); assert_int_equal(parameter[6].location, 0); assert_int_equal(parameter[6].location_sub, 0); assert_int_equal(parameter[7].result, f_console_result_none_e); assert_int_equal(parameter[7].locations.used, 0); + assert_int_equal(parameter[7].locations_sub.used, 0); assert_int_equal(parameter[7].values.used, 0); assert_int_equal(parameter[7].location, 0); assert_int_equal(parameter[7].location_sub, 0); assert_int_equal(parameter[8].result, f_console_result_none_e); assert_int_equal(parameter[8].locations.used, 0); + assert_int_equal(parameter[8].locations_sub.used, 0); assert_int_equal(parameter[8].values.used, 0); assert_int_equal(parameter[8].location, 0); assert_int_equal(parameter[8].location_sub, 0); @@ -217,54 +326,63 @@ void test__f_console_parameter_process__null_arguments(void **state) { assert_int_equal(parameter[0].result, f_console_result_none_e); assert_int_equal(parameter[0].locations.used, 0); + assert_int_equal(parameter[0].locations_sub.used, 0); assert_int_equal(parameter[0].values.used, 0); assert_int_equal(parameter[0].location, 0); assert_int_equal(parameter[0].location_sub, 0); assert_int_equal(parameter[1].result, f_console_result_none_e); assert_int_equal(parameter[1].locations.used, 0); + assert_int_equal(parameter[1].locations_sub.used, 0); assert_int_equal(parameter[1].values.used, 0); assert_int_equal(parameter[1].location, 0); assert_int_equal(parameter[1].location_sub, 0); assert_int_equal(parameter[2].result, f_console_result_none_e); assert_int_equal(parameter[2].locations.used, 0); + assert_int_equal(parameter[2].locations_sub.used, 0); assert_int_equal(parameter[2].values.used, 0); assert_int_equal(parameter[2].location, 0); assert_int_equal(parameter[2].location_sub, 0); assert_int_equal(parameter[3].result, f_console_result_none_e); assert_int_equal(parameter[3].locations.used, 0); + assert_int_equal(parameter[3].locations_sub.used, 0); assert_int_equal(parameter[3].values.used, 0); assert_int_equal(parameter[3].location, 0); assert_int_equal(parameter[3].location_sub, 0); assert_int_equal(parameter[4].result, f_console_result_none_e); assert_int_equal(parameter[4].locations.used, 0); + assert_int_equal(parameter[4].locations_sub.used, 0); assert_int_equal(parameter[4].values.used, 0); assert_int_equal(parameter[4].location, 0); assert_int_equal(parameter[4].location_sub, 0); assert_int_equal(parameter[5].result, f_console_result_none_e); assert_int_equal(parameter[5].locations.used, 0); + assert_int_equal(parameter[5].locations_sub.used, 0); assert_int_equal(parameter[5].values.used, 0); assert_int_equal(parameter[5].location, 0); assert_int_equal(parameter[5].location_sub, 0); assert_int_equal(parameter[6].result, f_console_result_none_e); assert_int_equal(parameter[6].locations.used, 0); + assert_int_equal(parameter[6].locations_sub.used, 0); assert_int_equal(parameter[6].values.used, 0); assert_int_equal(parameter[6].location, 0); assert_int_equal(parameter[6].location_sub, 0); assert_int_equal(parameter[7].result, f_console_result_none_e); assert_int_equal(parameter[7].locations.used, 0); + assert_int_equal(parameter[7].locations_sub.used, 0); assert_int_equal(parameter[7].values.used, 0); assert_int_equal(parameter[7].location, 0); assert_int_equal(parameter[7].location_sub, 0); assert_int_equal(parameter[8].result, f_console_result_none_e); assert_int_equal(parameter[8].locations.used, 0); + assert_int_equal(parameter[8].locations_sub.used, 0); assert_int_equal(parameter[8].values.used, 0); assert_int_equal(parameter[8].location, 0); assert_int_equal(parameter[8].location_sub, 0); @@ -286,10 +404,24 @@ void test__f_console_parameter_process__only_remaining(void **state) { "+h", "--help", "../`~!@#$%^&*()_-+={[}]:;\"'<,>./?", + "-soo", + "-oso", + "-oos", + "+soo", + "+oso", + "+oos", + "--seconds", + "--seconds", + "--seconds", + "++seconds", + "++seconds", + "++seconds", 0, }; - const f_console_arguments_t arguments = macro_f_console_arguments_t_initialize(7, argv, 0); + const int total = 19; + + const f_console_arguments_t arguments = macro_f_console_arguments_t_initialize(total, argv, 0); f_console_parameter_t parameter[] = { macro_f_console_parameter_t_initialize("f", 0, 0, 1, f_console_type_normal_e), @@ -364,7 +496,25 @@ void test__f_console_parameter_process__only_remaining(void **state) { assert_int_equal(parameter[8].location, 0); assert_int_equal(parameter[8].location_sub, 0); - assert_int_equal(parameters.remaining.used, 6); + assert_int_equal(parameters.remaining.used, total - 1); + assert_string_equal(argv[parameters.remaining.array[0]], argv[1]); + assert_string_equal(argv[parameters.remaining.array[1]], argv[2]); + assert_string_equal(argv[parameters.remaining.array[2]], argv[3]); + assert_string_equal(argv[parameters.remaining.array[3]], argv[4]); + assert_string_equal(argv[parameters.remaining.array[4]], argv[5]); + assert_string_equal(argv[parameters.remaining.array[5]], argv[6]); + assert_string_equal(argv[parameters.remaining.array[6]], argv[7]); + assert_string_equal(argv[parameters.remaining.array[7]], argv[8]); + assert_string_equal(argv[parameters.remaining.array[8]], argv[9]); + assert_string_equal(argv[parameters.remaining.array[9]], argv[10]); + assert_string_equal(argv[parameters.remaining.array[10]], argv[11]); + assert_string_equal(argv[parameters.remaining.array[11]], argv[12]); + assert_string_equal(argv[parameters.remaining.array[12]], argv[13]); + assert_string_equal(argv[parameters.remaining.array[13]], argv[14]); + assert_string_equal(argv[parameters.remaining.array[14]], argv[15]); + assert_string_equal(argv[parameters.remaining.array[15]], argv[16]); + assert_string_equal(argv[parameters.remaining.array[16]], argv[17]); + assert_string_equal(argv[parameters.remaining.array[17]], argv[18]); } f_console_parameters_delete(¶meters); @@ -388,7 +538,7 @@ void test__f_console_parameter_process__works(void **state) { "-f", "first", "-st", - "second", + "--second", "third", "other", "+F", @@ -402,10 +552,16 @@ void test__f_console_parameter_process__works(void **state) { "other", "free", "-4", + "+fast", + "-staff", + "-mMxx", + "mixed 1", + "mixed 2, value 1", + "mixed 2, value 2", 0, }; - const f_console_arguments_t arguments = macro_f_console_arguments_t_initialize(18, argv, 0); + const f_console_arguments_t arguments = macro_f_console_arguments_t_initialize(24, argv, 0); f_console_parameter_t parameter[] = { macro_f_console_parameter_t_initialize("f", 0, 0, 1, f_console_type_normal_e), @@ -416,10 +572,13 @@ void test__f_console_parameter_process__works(void **state) { macro_f_console_parameter_t_initialize(0, "sixth", 0, 1, f_console_type_normal_e), macro_f_console_parameter_t_initialize(0, "seventh", 0, 2, f_console_type_normal_e), macro_f_console_parameter_t_initialize("N", "not_found", 0, 0, f_console_type_normal_e), + macro_f_console_parameter_t_initialize("m", "mixed_1", 0, 1, f_console_type_normal_e), + macro_f_console_parameter_t_initialize("M", "mixed_2", 0, 2, f_console_type_normal_e), + macro_f_console_parameter_t_initialize("x", "mixed_3", 0, 0, f_console_type_normal_e), macro_f_console_parameter_t_initialize(0, 0, "other", 0, f_console_type_other_e), }; - f_console_parameters_t parameters = macro_f_console_parameters_t_initialize(parameter, 9); + f_console_parameters_t parameters = macro_f_console_parameters_t_initialize(parameter, 12); { const f_status_t status = f_console_parameter_process(arguments, ¶meters); @@ -428,77 +587,127 @@ void test__f_console_parameter_process__works(void **state) { assert_int_equal(parameter[0].result, f_console_result_additional_e); assert_int_equal(parameter[0].locations.used, 1); + assert_int_equal(parameter[0].locations_sub.used, 1); assert_int_equal(parameter[0].values.used, 1); assert_int_equal(parameter[0].location, 1); assert_int_equal(parameter[0].location_sub, 1); assert_int_equal(parameter[0].locations.array[0], 1); - assert_string_equal(argv[parameter[0].values.array[0]], "first"); + assert_int_equal(parameter[0].locations_sub.array[0], 1); + assert_string_equal(argv[parameter[0].values.array[0]], argv[2]); assert_int_equal(parameter[1].result, f_console_result_additional_e); assert_int_equal(parameter[1].locations.used, 1); + assert_int_equal(parameter[1].locations_sub.used, 1); assert_int_equal(parameter[1].values.used, 1); assert_int_equal(parameter[1].location, 3); assert_int_equal(parameter[1].location_sub, 1); assert_int_equal(parameter[1].locations.array[0], 3); - assert_string_equal(argv[parameter[1].values.array[0]], "second"); + assert_int_equal(parameter[1].locations_sub.array[0], 1); + assert_string_equal(argv[parameter[1].values.array[0]], argv[4]); assert_int_equal(parameter[2].result, f_console_result_additional_e); assert_int_equal(parameter[2].locations.used, 1); + assert_int_equal(parameter[2].locations_sub.used, 1); assert_int_equal(parameter[2].values.used, 1); assert_int_equal(parameter[2].location, 3); assert_int_equal(parameter[2].location_sub, 2); assert_int_equal(parameter[2].locations.array[0], 3); - assert_string_equal(argv[parameter[2].values.array[0]], "third"); + assert_int_equal(parameter[2].locations_sub.array[0], 2); + assert_string_equal(argv[parameter[2].values.array[0]], argv[5]); assert_int_equal(parameter[3].result, f_console_result_found_e); assert_int_equal(parameter[3].locations.used, 1); + assert_int_equal(parameter[3].locations_sub.used, 1); assert_int_equal(parameter[3].values.used, 0); assert_int_equal(parameter[3].location, 7); assert_int_equal(parameter[3].location_sub, 1); assert_int_equal(parameter[3].locations.array[0], 7); + assert_int_equal(parameter[3].locations_sub.array[0], 1); assert_int_equal(parameter[4].result, f_console_result_additional_e); assert_int_equal(parameter[4].locations.used, 1); + assert_int_equal(parameter[4].locations_sub.used, 1); assert_int_equal(parameter[4].values.used, 1); assert_int_equal(parameter[4].location, 8); assert_int_equal(parameter[4].location_sub, 0); assert_int_equal(parameter[4].locations.array[0], 8); - assert_string_equal(argv[parameter[4].values.array[0]], "fifth"); + assert_int_equal(parameter[4].locations_sub.array[0], 0); + assert_string_equal(argv[parameter[4].values.array[0]], argv[9]); assert_int_equal(parameter[5].result, f_console_result_additional_e); assert_int_equal(parameter[5].locations.used, 1); + assert_int_equal(parameter[5].locations_sub.used, 1); assert_int_equal(parameter[5].values.used, 1); assert_int_equal(parameter[5].location, 10); assert_int_equal(parameter[5].location_sub, 0); assert_int_equal(parameter[5].locations.array[0], 10); - assert_string_equal(argv[parameter[5].values.array[0]], "sixth"); + assert_int_equal(parameter[5].locations_sub.array[0], 0); + assert_string_equal(argv[parameter[5].values.array[0]], argv[11]); assert_int_equal(parameter[6].result, f_console_result_additional_e); assert_int_equal(parameter[6].locations.used, 1); + assert_int_equal(parameter[6].locations_sub.used, 1); assert_int_equal(parameter[6].values.used, 2); assert_int_equal(parameter[6].location, 12); assert_int_equal(parameter[6].location_sub, 0); assert_int_equal(parameter[6].locations.array[0], 12); - assert_string_equal(argv[parameter[6].values.array[0]], "seventh"); - assert_string_equal(argv[parameter[6].values.array[1]], "7"); + assert_int_equal(parameter[6].locations_sub.array[0], 0); + assert_string_equal(argv[parameter[6].values.array[0]], argv[13]); + assert_string_equal(argv[parameter[6].values.array[1]], argv[14]); assert_int_equal(parameter[7].result, f_console_result_none_e); assert_int_equal(parameter[7].locations.used, 0); + assert_int_equal(parameter[7].locations_sub.used, 0); assert_int_equal(parameter[7].values.used, 0); assert_int_equal(parameter[7].location, 0); assert_int_equal(parameter[7].location_sub, 0); - assert_int_equal(parameter[8].result, f_console_result_found_e); - assert_int_equal(parameter[8].locations.used, 2); - assert_int_equal(parameter[8].values.used, 0); - assert_int_equal(parameter[8].location, 15); - assert_int_equal(parameter[8].location_sub, 0); - assert_int_equal(parameter[8].locations.array[0], 6); - assert_int_equal(parameter[8].locations.array[1], 15); - - assert_int_equal(parameters.remaining.used, 2); - assert_string_equal(argv[parameters.remaining.array[0]], "free"); - assert_string_equal(argv[parameters.remaining.array[1]], "-4"); + assert_int_equal(parameter[8].result, f_console_result_additional_e); + assert_int_equal(parameter[8].locations.used, 1); + assert_int_equal(parameter[8].locations_sub.used, 1); + assert_int_equal(parameter[8].values.used, 1); + assert_int_equal(parameter[8].location, 20); + assert_int_equal(parameter[8].location_sub, 1); + assert_int_equal(parameter[8].locations.array[0], 20); + assert_int_equal(parameter[8].locations_sub.array[0], 1); + assert_string_equal(argv[parameter[8].values.array[0]], argv[21]); + + assert_int_equal(parameter[9].result, f_console_result_additional_e); + assert_int_equal(parameter[9].locations.used, 1); + assert_int_equal(parameter[9].locations_sub.used, 1); + assert_int_equal(parameter[9].values.used, 2); + assert_int_equal(parameter[9].location, 20); + assert_int_equal(parameter[9].location_sub, 2); + assert_int_equal(parameter[9].locations.array[0], 20); + assert_int_equal(parameter[9].locations_sub.array[0], 2); + assert_string_equal(argv[parameter[9].values.array[0]], argv[22]); + assert_string_equal(argv[parameter[9].values.array[1]], argv[23]); + + assert_int_equal(parameter[10].result, f_console_result_found_e); + assert_int_equal(parameter[10].locations.used, 1); + assert_int_equal(parameter[10].locations_sub.used, 2); + assert_int_equal(parameter[10].values.used, 0); + assert_int_equal(parameter[10].location, 20); + assert_int_equal(parameter[10].location_sub, 4); + assert_int_equal(parameter[10].locations.array[0], 20); + assert_int_equal(parameter[10].locations_sub.array[0], 3); + assert_int_equal(parameter[10].locations_sub.array[1], 4); + + assert_int_equal(parameter[11].result, f_console_result_found_e); + assert_int_equal(parameter[11].locations.used, 2); + assert_int_equal(parameter[11].locations_sub.used, 2); + assert_int_equal(parameter[11].values.used, 0); + assert_int_equal(parameter[11].location, 15); + assert_int_equal(parameter[11].location_sub, 0); + assert_int_equal(parameter[11].locations.array[0], 6); + assert_int_equal(parameter[11].locations.array[1], 15); + assert_int_equal(parameter[11].locations_sub.array[0], 0); + + assert_int_equal(parameters.remaining.used, 4); + assert_string_equal(argv[parameters.remaining.array[0]], argv[16]); + assert_string_equal(argv[parameters.remaining.array[1]], argv[17]); + assert_string_equal(argv[parameters.remaining.array[2]], argv[18]); + assert_string_equal(argv[parameters.remaining.array[3]], argv[19]); } f_console_parameters_delete(¶meters); diff --git a/level_0/f_console/tests/unit/c/test-console-parameter_process.h b/level_0/f_console/tests/unit/c/test-console-parameter_process.h index 1b8e3e4..97bc01e 100644 --- a/level_0/f_console/tests/unit/c/test-console-parameter_process.h +++ b/level_0/f_console/tests/unit/c/test-console-parameter_process.h @@ -13,6 +13,13 @@ // f_console_parameter_process() only returns memory failures. /** + * Test that function works with incomplete arguments. + * + * @see f_console_parameter_process() + */ +extern void test__f_console_parameter_process__incomplete_arguments(void **state); + +/** * Test that function works with no (argv) arguments (but does have program name). * * @see f_console_parameter_process() diff --git a/level_0/f_console/tests/unit/c/test-console.c b/level_0/f_console/tests/unit/c/test-console.c index 055d99e..fe9a67a 100644 --- a/level_0/f_console/tests/unit/c/test-console.c +++ b/level_0/f_console/tests/unit/c/test-console.c @@ -31,6 +31,7 @@ int main(void) { cmocka_unit_test(test__f_console_parameter_prioritize_right__fails), cmocka_unit_test(test__f_console_parameter_prioritize_right__works), + cmocka_unit_test(test__f_console_parameter_process__incomplete_arguments), cmocka_unit_test(test__f_console_parameter_process__no_arguments_no_program), cmocka_unit_test(test__f_console_parameter_process__no_arguments), cmocka_unit_test(test__f_console_parameter_process__null_arguments), -- 1.8.3.1