]> Kevux Git Server - fll/commitdiff
Bugfix: Short console arguments should not match when a single invalid exists.
authorKevin Day <kevin@kevux.org>
Mon, 23 Jan 2023 02:58:07 +0000 (20:58 -0600)
committerKevin Day <kevin@kevux.org>
Mon, 23 Jan 2023 04:08:31 +0000 (22:08 -0600)
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
level_0/f_console/c/console.h
level_0/f_console/tests/unit/c/test-console-parameter_process.c
level_0/f_console/tests/unit/c/test-console-parameter_process.h
level_0/f_console/tests/unit/c/test-console.c

index 52f14f256926e9febfafd36e0977f1fe306f8f0c..52127736383443d2e1de3c41e5e78b2fad4a0a0d 100644 (file)
@@ -165,30 +165,30 @@ extern "C" {
     f_status_t status = f_string_dynamics_increase_by(arguments.argc, &parameters->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, &parameters->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, &parameters->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, &parameters->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, &parameters->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, &parameters->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, &parameters->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, &parameters->array[i].locations);
           if (F_status_is_error(status)) break;
 
           status = f_array_lengths_increase(F_memory_default_allocation_small_d, &parameters->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, &parameters->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, &parameters->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;
   }
index 4f6df8b7a7513617cad0ce65b64addd5efaf8e9f..04319b9be96bbb9c382d5bca6b6271df96c326b3 100644 (file)
@@ -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_
index b43f48e7a935306683ace7dd75e6c4f039270b00..0f1db0216edc1646659bfbf3a60e7bcaa89a74bd 100644 (file)
@@ -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, &parameters);
+
+    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(&parameters);
+}
+
 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(&parameters);
@@ -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, &parameters);
@@ -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(&parameters);
index 1b8e3e45c2a486761ad108217ee19307611dee70..97bc01e97321f803abdf63fd75722a13a6b8b152 100644 (file)
 // 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()
index 055d99eabe3358831ab51ddeab57fcc465a823ab..fe9a67a87eceae9fdd3d090e091d07f3135e3c51 100644 (file)
@@ -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),