]> Kevux Git Server - fll/commitdiff
Feature: Add f_string_dynamic_strip_null() and f_string_dynamic_strip_null_range().
authorKevin Day <thekevinday@gmail.com>
Tue, 16 Jan 2024 14:22:03 +0000 (08:22 -0600)
committerKevin Day <thekevinday@gmail.com>
Tue, 16 Jan 2024 14:22:03 +0000 (08:22 -0600)
The ability to strip out NULLs from a given string as a common function is needed.

Provide two similar but different functions.
The f_string_dynamic_strip_null() moves the NULLs to the end of the string and the shrinks the string used length as appropriate.
The f_string_dynamic_strip_null_range() shifts all of the NULLs found to the end of the given range without modifying the array used length.

Unit tests are added.

Only basic logic is applied and so there is no especially focused optimization in the parsing logic.

level_0/f_string/c/string/dynamic.c
level_0/f_string/c/string/dynamic.h
level_0/f_string/data/build/settings-tests
level_0/f_string/tests/unit/c/test-string-dynamic_strip_null.c [new file with mode: 0644]
level_0/f_string/tests/unit/c/test-string-dynamic_strip_null.h [new file with mode: 0644]
level_0/f_string/tests/unit/c/test-string-dynamic_strip_null_range.c [new file with mode: 0644]
level_0/f_string/tests/unit/c/test-string-dynamic_strip_null_range.h [new file with mode: 0644]
level_0/f_string/tests/unit/c/test-string.c
level_0/f_string/tests/unit/c/test-string.h

index 31f95cb986c486b86da0642676bfa2ad7da01575..11acd723ba92fc91f38771bf3d2515b78be6d404 100644 (file)
@@ -622,6 +622,105 @@ extern "C" {
   }
 #endif // _di_f_string_dynamic_seek_to_
 
+#ifndef _di_f_string_dynamic_strip_null_
+  f_status_t f_string_dynamic_strip_null(f_string_dynamic_t * const buffer) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!buffer) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (!buffer->used) return F_data_not;
+
+    // Skip past trailing NULLs.
+    while (buffer->used && !buffer->string[buffer->used - 1]) {
+      --buffer->used;
+    } // while
+
+    if (!buffer->used) return F_okay;
+
+    f_number_unsigned_t i = buffer->used - 1;
+    f_number_unsigned_t j = 0;
+
+    do {
+      if (!buffer->string[i]) {
+
+        // Set index j to the left-most consecutive NULL from index i, with index i being the right-most NULL.
+        if (i) {
+          for (j = i - 1; j && !buffer->string[j]; --j) {
+            // Do nothing.
+          } // for
+
+          if (buffer->string[j]) {
+            ++j;
+          }
+        }
+        else {
+          j = i;
+        }
+
+        memmove(buffer->string + j, buffer->string + i + 1, buffer->used - i);
+        memset(buffer->string + (buffer->used - (i - j) - 1), 0, (i - j) + 1);
+
+        buffer->used -= (i - j) + 1;
+        i = j;
+      }
+
+    } while (i--);
+
+    return F_okay;
+  }
+#endif // _di_f_string_dynamic_strip_null_
+
+#ifndef _di_f_string_dynamic_strip_null_range_
+  f_status_t f_string_dynamic_strip_null_range(const f_range_t range, f_string_dynamic_t * const buffer) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!buffer) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (!buffer->used) return F_data_not;
+    if (range.start > range.stop) return F_data_not_stop;
+    if (range.start >= buffer->used) return F_data_not_eos;
+
+    f_number_unsigned_t last = range.stop;
+    f_number_unsigned_t i = range.stop + 1;
+    f_number_unsigned_t j = 0;
+
+    // Skip past trailing NULLs.
+    while (i-- > range.start && i) {
+      if (buffer->string[i]) break;
+    } // while
+
+    if (i) {
+      do {
+        if (!buffer->string[i]) {
+
+          // Set index j to the left-most consecutive NULL from index i, with index i being the right-most NULL.
+          if (i) {
+            for (j = i - 1; j && !buffer->string[j]; --j) {
+              // Do nothing.
+            } // for
+
+            if (buffer->string[j]) {
+              ++j;
+            }
+          }
+          else {
+            j = i;
+          }
+
+          memmove(buffer->string + j, buffer->string + i + 1, last - i);
+          memset(buffer->string + (last - (i - j)), 0, (i - j) + 1);
+
+          last -= (i - j) + 1;
+          i = j;
+        }
+
+      } while (i-- > range.start);
+    }
+
+    return F_okay;
+  }
+#endif // _di_f_string_dynamic_strip_null_range_
+
 #ifndef _di_f_string_dynamic_terminate_
   f_status_t f_string_dynamic_terminate(f_string_dynamic_t * const destination) {
     #ifndef _di_level_0_parameter_checking_
index 29ba25e468181855f46f01b4bb5e134e8acdcfc5..d097ab85ae0c43b5bf4d7f42ece9942a65fe123a 100644 (file)
@@ -742,6 +742,52 @@ extern "C" {
 #endif // _di_f_string_dynamic_seek_to_
 
 /**
+ * String all NULLs from the given string.
+ *
+ * This does not resize the string.
+ * The string used length of the buffer is shrunk based on the NULLs removed.
+ *
+ * @param buffer
+ *   The string to strip the NULLs from.
+ *
+ * @return
+ *   F_okay on success.
+ *   F_data_not if source length is 0.
+ *
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_string_too_large (with error bit) if the combined string is too large.
+ */
+#ifndef _di_f_string_dynamic_strip_null_
+  extern f_status_t f_string_dynamic_strip_null(f_string_dynamic_t * const buffer);
+#endif // _di_f_string_dynamic_strip_null_
+
+/**
+ * String all NULLs from the given string within the specified range.
+ *
+ * This does not resize the string.
+ * Unlike f_string_dynamic_strip_null(), this does not alter the string used length of the buffer.
+ *
+ * Any found NULLs are moved to the end of the range in the buffer.
+ *
+ * @param range
+ *   The given range within the buffer to strip.
+ * @param buffer
+ *   The string to strip the NULLs from.
+ *
+ * @return
+ *   F_okay on success.
+ *   F_data_not if source length is 0.
+ *   F_data_not_eos if range.start >= source.used.
+ *   F_data_not_stop if range.start > range.stop.
+ *
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_string_too_large (with error bit) if the combined string is too large.
+ */
+#ifndef _di_f_string_dynamic_strip_null_range_
+  extern f_status_t f_string_dynamic_strip_null_range(const f_range_t range, f_string_dynamic_t * const buffer);
+#endif // _di_f_string_dynamic_strip_null_range_
+
+/**
  * Guarantee that an end of string (NULL) exists at the end of the string.
  *
  * This is intended to be used for anything requiring NULL terminated strings.
index 0bca0f8a3d5e6bb1e0a2a0c639e77dc1e0808b73..9ff452df8e10b16c16696b9923282fc543815bb3 100644 (file)
@@ -35,6 +35,7 @@ build_sources_program test-string-dynamic_partial_mish.c test-string-dynamic_par
 build_sources_program test-string-dynamic_partial_prepend.c test-string-dynamic_partial_prepend_assure.c test-string-dynamic_partial_prepend_assure_nulless.c test-string-dynamic_partial_prepend_nulless.c
 build_sources_program test-string-dynamic_prepend.c test-string-dynamic_prepend_assure.c test-string-dynamic_prepend_assure_nulless.c test-string-dynamic_prepend_nulless.c
 build_sources_program test-string-dynamic_seek_line.c test-string-dynamic_seek_line_to.c test-string-dynamic_seek_to.c
+build_sources_program test-string-dynamic_strip_null.c test-string-dynamic_strip_null_range.c
 build_sources_program test-string-dynamic_terminate.c test-string-dynamic_terminate_after.c
 build_sources_program test-string-dynamics_append.c test-string-dynamics_append_all.c test-string-dynamicss_append.c test-string-dynamicss_append_all.c
 build_sources_program test-string-dynamics_delete_callback.c test-string-dynamics_destroy_callback.c
diff --git a/level_0/f_string/tests/unit/c/test-string-dynamic_strip_null.c b/level_0/f_string/tests/unit/c/test-string-dynamic_strip_null.c
new file mode 100644 (file)
index 0000000..3e5eac8
--- /dev/null
@@ -0,0 +1,141 @@
+#include "test-string.h"
+#include "test-string-dynamic_strip_null.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_string_dynamic_strip_null__returns_data_not(void **state) {
+
+  f_string_static_t buffer = f_string_static_t_initialize;
+
+  {
+    const f_status_t status = f_string_dynamic_strip_null(&buffer);
+
+    assert_int_equal(status, F_data_not);
+  }
+}
+
+void test__f_string_dynamic_strip_null__works(void **state) {
+
+  const f_string_static_t sources[] = {
+
+    // First Set.
+    macro_f_string_static_t_initialize_1("test", 0, 4),
+    macro_f_string_static_t_initialize_1("test", 0, 5),
+    macro_f_string_static_t_initialize_1("te\0st", 0, 5),
+    macro_f_string_static_t_initialize_1("te\0st", 0, 6),
+    macro_f_string_static_t_initialize_1("te\0\0st", 0, 6),
+    macro_f_string_static_t_initialize_1("te\0\0st", 0, 7),
+    macro_f_string_static_t_initialize_1("te\0\0s\0t", 0, 7),
+    macro_f_string_static_t_initialize_1("te\0\0s\0t", 0, 8),
+    macro_f_string_static_t_initialize_1("te\0\0s\0\0\0t", 0, 9),
+    macro_f_string_static_t_initialize_1("te\0\0s\0\0\0t", 0, 10),
+
+    // Second Set.
+    macro_f_string_static_t_initialize_1("test", 0, 4),
+    macro_f_string_static_t_initialize_1("test", 0, 5),
+    macro_f_string_static_t_initialize_1("te\0st", 0, 5),
+    macro_f_string_static_t_initialize_1("te\0st", 0, 6),
+    macro_f_string_static_t_initialize_1("te\0\0st", 0, 6),
+    macro_f_string_static_t_initialize_1("te\0\0st", 0, 7),
+    macro_f_string_static_t_initialize_1("te\0\0s\0t", 0, 7),
+    macro_f_string_static_t_initialize_1("te\0\0s\0t", 0, 8),
+    macro_f_string_static_t_initialize_1("te\0\0s\0\0\0t", 0, 9),
+    macro_f_string_static_t_initialize_1("te\0\0s\0\0\0t", 0, 10),
+
+    // Third Set.
+    macro_f_string_static_t_initialize_1("\0\0test", 0, 6),
+    macro_f_string_static_t_initialize_1("\0\0test", 0, 7),
+    macro_f_string_static_t_initialize_1("\0\0te\0st", 0, 7),
+    macro_f_string_static_t_initialize_1("\0\0te\0st", 0, 8),
+    macro_f_string_static_t_initialize_1("\0\0te\0\0st", 0, 8),
+    macro_f_string_static_t_initialize_1("\0\0te\0\0st", 0, 9),
+    macro_f_string_static_t_initialize_1("\0\0te\0\0s\0t", 0, 9),
+    macro_f_string_static_t_initialize_1("\0\0te\0\0s\0t", 0, 10),
+    macro_f_string_static_t_initialize_1("\0\0te\0\0s\0\0\0t", 0, 11),
+    macro_f_string_static_t_initialize_1("\0\0te\0\0s\0\0\0t", 0, 12),
+
+    // Fourth Set.
+    macro_f_string_static_t_initialize_1("\0\0\0\0", 0, 4),
+    macro_f_string_static_t_initialize_1("\0\0\0\0", 0, 4),
+    macro_f_string_static_t_initialize_1("\0", 0, 1),
+    macro_f_string_static_t_initialize_1("t", 0, 1),
+  };
+
+  const f_string_static_t expects[] = {
+
+    // First Set.
+    macro_f_string_static_t_initialize_1("test", 0, 4),
+    macro_f_string_static_t_initialize_1("test", 0, 4),
+    macro_f_string_static_t_initialize_1("test\0", 0, 4),
+    macro_f_string_static_t_initialize_1("test\0", 0, 4),
+    macro_f_string_static_t_initialize_1("test\0\0", 0, 4),
+    macro_f_string_static_t_initialize_1("test\0\0", 0, 4),
+    macro_f_string_static_t_initialize_1("test\0\0\0", 0, 4),
+    macro_f_string_static_t_initialize_1("test\0\0\0", 0, 4),
+    macro_f_string_static_t_initialize_1("test\0\0\0\0\0", 0, 4),
+    macro_f_string_static_t_initialize_1("test\0\0\0\0\0", 0, 4),
+
+    // Second Set.
+    macro_f_string_static_t_initialize_1("test", 0, 4),
+    macro_f_string_static_t_initialize_1("test", 0, 4),
+    macro_f_string_static_t_initialize_1("test\0", 0, 4),
+    macro_f_string_static_t_initialize_1("test\0", 0, 4),
+    macro_f_string_static_t_initialize_1("test\0\0", 0, 4),
+    macro_f_string_static_t_initialize_1("test\0\0", 0, 4),
+    macro_f_string_static_t_initialize_1("test\0\0\0", 0, 4),
+    macro_f_string_static_t_initialize_1("test\0\0\0", 0, 4),
+    macro_f_string_static_t_initialize_1("test\0\0\0\0\0", 0, 4),
+    macro_f_string_static_t_initialize_1("test\0\0\0\0\0", 0, 4),
+
+    // Third Set.
+    macro_f_string_static_t_initialize_1("test\0\0", 0, 4),
+    macro_f_string_static_t_initialize_1("test\0\0", 0, 4),
+    macro_f_string_static_t_initialize_1("test\0\0\0", 0, 4),
+    macro_f_string_static_t_initialize_1("test\0\0\0", 0, 4),
+    macro_f_string_static_t_initialize_1("test\0\0\0\0", 0, 4),
+    macro_f_string_static_t_initialize_1("test\0\0\0\0", 0, 4),
+    macro_f_string_static_t_initialize_1("test\0\0\0\0\0", 0, 4),
+    macro_f_string_static_t_initialize_1("test\0\0\0\0\0", 0, 4),
+    macro_f_string_static_t_initialize_1("test\0\0\0\0\0\0\0", 0, 4),
+    macro_f_string_static_t_initialize_1("test\0\0\0\0\0\0\0", 0, 4),
+
+    // Fourth Set.
+    macro_f_string_static_t_initialize_1("\0\0\0\0", 0, 0),
+    macro_f_string_static_t_initialize_1("\0\0\0\0", 0, 0),
+    macro_f_string_static_t_initialize_1("\0", 0, 0),
+    macro_f_string_static_t_initialize_1("t", 0, 1),
+  };
+
+  for (uint8_t i = 0; i < 34; ++i) {
+
+    char string[sources[i].used];
+    f_string_static_t buffer = macro_f_string_static_t_initialize_1(string, 0, sources[i].used);
+
+    memcpy(string, sources[i].string, sources[i].used);
+
+    const f_status_t status = f_string_dynamic_strip_null(&buffer);
+
+    assert_int_equal(status, F_okay);
+    assert_int_equal(buffer.used, expects[i].used);
+
+    // Compare strings using integer tests because assert_string_equal() assumes NULL terminated strings (using souces to confirm that the NULLs are moved).
+    for (uint8_t j = 0; j < sources[i].used; ++j) {
+      assert_int_equal(buffer.string[j], expects[i].string[j]);
+    } // for
+  } // for
+}
+
+void test__f_string_dynamic_strip_null__parameter_checking(void **state) {
+
+  {
+    const f_status_t status = f_string_dynamic_strip_null(0);
+
+    assert_int_equal(status, F_status_set_error(F_parameter));
+  }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_0/f_string/tests/unit/c/test-string-dynamic_strip_null.h b/level_0/f_string/tests/unit/c/test-string-dynamic_strip_null.h
new file mode 100644 (file)
index 0000000..35d05d5
--- /dev/null
@@ -0,0 +1,34 @@
+/**
+ * FLL - Level 0
+ *
+ * Project: String
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the array types in the type project.
+ */
+#ifndef _TEST__F_dynamic_strip_null_h
+#define _TEST__F_dynamic_strip_null_h
+
+/**
+ * Test that the function returns F_data_not because the buffer is empty.
+ *
+ * @see f_string_dynamic_strip_null()
+ */
+extern void test__f_string_dynamic_strip_null__returns_data_not(void **state);
+
+/**
+ * Test that the function works.
+ *
+ * @see f_string_dynamic_strip_null()
+ */
+extern void test__f_string_dynamic_strip_null__works(void **state);
+
+/**
+ * Test that the function correctly fails on invalid parameter.
+ *
+ * @see f_string_dynamic_strip_null()
+ */
+extern void test__f_string_dynamic_strip_null__parameter_checking(void **state);
+
+#endif // _TEST__F_dynamic_strip_null_h
diff --git a/level_0/f_string/tests/unit/c/test-string-dynamic_strip_null_range.c b/level_0/f_string/tests/unit/c/test-string-dynamic_strip_null_range.c
new file mode 100644 (file)
index 0000000..180b319
--- /dev/null
@@ -0,0 +1,213 @@
+#include "test-string.h"
+#include "test-string-dynamic_strip_null_range.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_string_dynamic_strip_null_range__returns_data_not(void **state) {
+
+  f_string_static_t buffer = f_string_static_t_initialize;
+  const f_range_t range = macro_f_range_t_initialize_1(0, 0);
+
+  {
+    const f_status_t status = f_string_dynamic_strip_null_range(range, &buffer);
+
+    assert_int_equal(status, F_data_not);
+  }
+}
+
+void test__f_string_dynamic_strip_null_range__returns_data_not_eos(void **state) {
+
+  f_string_static_t buffer = macro_f_string_static_t_initialize_1("test", 0, 4);
+  const f_range_t range = macro_f_range_t_initialize_1(buffer.used, buffer.used);
+
+  {
+    const f_status_t status = f_string_dynamic_strip_null_range(range, &buffer);
+
+    assert_int_equal(status, F_data_not_eos);
+  }
+}
+
+void test__f_string_dynamic_strip_null_range__returns_data_not_stop(void **state) {
+
+  f_string_static_t buffer = macro_f_string_static_t_initialize_1("test", 0, 4);
+  const f_range_t range = f_range_t_initialize;
+
+  {
+    const f_status_t status = f_string_dynamic_strip_null_range(range, &buffer);
+
+    assert_int_equal(status, F_data_not_stop);
+  }
+}
+
+void test__f_string_dynamic_strip_null_range__works(void **state) {
+
+  const f_string_static_t sources[] = {
+
+    // First Set.
+    macro_f_string_static_t_initialize_1("test", 0, 4),
+    macro_f_string_static_t_initialize_1("test", 0, 5),
+    macro_f_string_static_t_initialize_1("te\0st", 0, 5),
+    macro_f_string_static_t_initialize_1("te\0st", 0, 6),
+    macro_f_string_static_t_initialize_1("te\0\0st", 0, 6),
+    macro_f_string_static_t_initialize_1("te\0\0st", 0, 7),
+    macro_f_string_static_t_initialize_1("te\0\0s\0t", 0, 7),
+    macro_f_string_static_t_initialize_1("te\0\0s\0t", 0, 8),
+    macro_f_string_static_t_initialize_1("te\0\0s\0\0\0t", 0, 9),
+    macro_f_string_static_t_initialize_1("te\0\0s\0\0\0t", 0, 10),
+
+    // Second Set.
+    macro_f_string_static_t_initialize_1("test", 0, 4),
+    macro_f_string_static_t_initialize_1("test", 0, 5),
+    macro_f_string_static_t_initialize_1("te\0st", 0, 5),
+    macro_f_string_static_t_initialize_1("te\0st", 0, 6),
+    macro_f_string_static_t_initialize_1("te\0\0st", 0, 6),
+    macro_f_string_static_t_initialize_1("te\0\0st", 0, 7),
+    macro_f_string_static_t_initialize_1("te\0\0s\0t", 0, 7),
+    macro_f_string_static_t_initialize_1("te\0\0s\0t", 0, 8),
+    macro_f_string_static_t_initialize_1("te\0\0s\0\0\0t", 0, 9),
+    macro_f_string_static_t_initialize_1("te\0\0s\0\0\0t", 0, 10),
+
+    // Third Set.
+    macro_f_string_static_t_initialize_1("\0\0test", 0, 6),
+    macro_f_string_static_t_initialize_1("\0\0test", 0, 7),
+    macro_f_string_static_t_initialize_1("\0\0te\0st", 0, 7),
+    macro_f_string_static_t_initialize_1("\0\0te\0st", 0, 8),
+    macro_f_string_static_t_initialize_1("\0\0te\0\0st", 0, 8),
+    macro_f_string_static_t_initialize_1("\0\0te\0\0st", 0, 9),
+    macro_f_string_static_t_initialize_1("\0\0te\0\0s\0t", 0, 9),
+    macro_f_string_static_t_initialize_1("\0\0te\0\0s\0t", 0, 10),
+    macro_f_string_static_t_initialize_1("\0\0te\0\0s\0\0\0t", 0, 11),
+    macro_f_string_static_t_initialize_1("\0\0te\0\0s\0\0\0t", 0, 12),
+
+    // Fourth Set.
+    macro_f_string_static_t_initialize_1("\0\0\0\0", 0, 4),
+    macro_f_string_static_t_initialize_1("\0\0\0\0", 0, 4),
+    macro_f_string_static_t_initialize_1("\0", 0, 1),
+    macro_f_string_static_t_initialize_1("t", 0, 1),
+  };
+
+  const f_string_static_t expects[] = {
+
+    // First Set.
+    macro_f_string_static_t_initialize_1("test", 0, 4),
+    macro_f_string_static_t_initialize_1("test", 0, 5),
+    macro_f_string_static_t_initialize_1("test\0", 0, 5),
+    macro_f_string_static_t_initialize_1("test\0", 0, 6),
+    macro_f_string_static_t_initialize_1("test\0\0", 0, 6),
+    macro_f_string_static_t_initialize_1("test\0\0", 0, 7),
+    macro_f_string_static_t_initialize_1("test\0\0\0", 0, 7),
+    macro_f_string_static_t_initialize_1("test\0\0\0", 0, 8),
+    macro_f_string_static_t_initialize_1("test\0\0\0\0\0", 0, 9),
+    macro_f_string_static_t_initialize_1("test\0\0\0\0\0", 0, 10),
+
+    // Second Set.
+    macro_f_string_static_t_initialize_1("test", 0, 4),
+    macro_f_string_static_t_initialize_1("test", 0, 5),
+    macro_f_string_static_t_initialize_1("test\0", 0, 5),
+    macro_f_string_static_t_initialize_1("test\0", 0, 6),
+    macro_f_string_static_t_initialize_1("test\0\0", 0, 6),
+    macro_f_string_static_t_initialize_1("test\0\0", 0, 7),
+    macro_f_string_static_t_initialize_1("test\0\0\0", 0, 7),
+    macro_f_string_static_t_initialize_1("test\0\0\0", 0, 8),
+    macro_f_string_static_t_initialize_1("test\0\0\0\0\0", 0, 9),
+    macro_f_string_static_t_initialize_1("test\0\0\0\0\0", 0, 10),
+
+    // Third Set.
+    macro_f_string_static_t_initialize_1("te\0\0st", 0, 6),
+    macro_f_string_static_t_initialize_1("te\0\0st", 0, 7),
+    macro_f_string_static_t_initialize_1("te\0\0\0st", 0, 7),
+    macro_f_string_static_t_initialize_1("te\0\0\0st", 0, 8),
+    macro_f_string_static_t_initialize_1("te\0\0\0\0st", 0, 8),
+    macro_f_string_static_t_initialize_1("te\0\0\0\0st", 0, 9),
+    macro_f_string_static_t_initialize_1("te\0\0\0\0s\0t", 0, 9),
+    macro_f_string_static_t_initialize_1("te\0\0\0\0s\0t", 0, 10),
+    macro_f_string_static_t_initialize_1("te\0\0\0\0s\0\0\0t", 0, 11),
+    macro_f_string_static_t_initialize_1("te\0\0\0\0s\0\0\0t", 0, 12),
+
+    // Fourth Set.
+    macro_f_string_static_t_initialize_1("\0\0\0\0", 0, 4),
+    macro_f_string_static_t_initialize_1("\0\0\0\0", 0, 4),
+    macro_f_string_static_t_initialize_1("\0", 0, 1),
+    macro_f_string_static_t_initialize_1("t", 0, 1),
+  };
+
+  const f_range_t ranges[] = {
+
+    // First Set.
+    macro_f_range_t_initialize_1(0, sources[0].used - 1),
+    macro_f_range_t_initialize_1(0, sources[1].used - 1),
+    macro_f_range_t_initialize_1(0, sources[2].used - 1),
+    macro_f_range_t_initialize_1(0, sources[3].used - 1),
+    macro_f_range_t_initialize_1(0, sources[4].used - 1),
+    macro_f_range_t_initialize_1(0, sources[5].used - 1),
+    macro_f_range_t_initialize_1(0, sources[6].used - 1),
+    macro_f_range_t_initialize_1(0, sources[7].used - 1),
+    macro_f_range_t_initialize_1(0, sources[8].used - 1),
+    macro_f_range_t_initialize_1(0, sources[9].used - 1),
+
+    // Second Set.
+    macro_f_range_t_initialize_1(2, 3),
+    macro_f_range_t_initialize_1(2, 3),
+    macro_f_range_t_initialize_1(2, 4),
+    macro_f_range_t_initialize_1(2, 4),
+    macro_f_range_t_initialize_1(2, 5),
+    macro_f_range_t_initialize_1(2, 5),
+    macro_f_range_t_initialize_1(2, 6),
+    macro_f_range_t_initialize_1(2, 6),
+    macro_f_range_t_initialize_1(2, 8),
+    macro_f_range_t_initialize_1(2, 8),
+
+    // Third Set.
+    macro_f_range_t_initialize_1(0, 3),
+    macro_f_range_t_initialize_1(0, 3),
+    macro_f_range_t_initialize_1(0, 3),
+    macro_f_range_t_initialize_1(0, 3),
+    macro_f_range_t_initialize_1(0, 3),
+    macro_f_range_t_initialize_1(0, 3),
+    macro_f_range_t_initialize_1(0, 3),
+    macro_f_range_t_initialize_1(0, 3),
+    macro_f_range_t_initialize_1(0, 3),
+    macro_f_range_t_initialize_1(0, 3),
+
+    // Fourth Set.
+    macro_f_range_t_initialize_1(0, 0),
+    macro_f_range_t_initialize_1(0, 3),
+    macro_f_range_t_initialize_1(0, 0),
+    macro_f_range_t_initialize_1(0, 0),
+  };
+
+  for (uint8_t i = 0; i < 34; ++i) {
+
+    char string[sources[i].used];
+    f_string_static_t buffer = macro_f_string_static_t_initialize_1(string, 0, sources[i].used);
+
+    memcpy(string, sources[i].string, sources[i].used);
+
+    const f_status_t status = f_string_dynamic_strip_null_range(ranges[i], &buffer);
+
+    assert_int_equal(status, F_okay);
+    assert_int_equal(buffer.used, expects[i].used);
+
+    // Compare strings using integer tests because assert_string_equal() assumes NULL terminated strings.
+    for (uint8_t j = 0; j < buffer.used; ++j) {
+      assert_int_equal(buffer.string[j], expects[i].string[j]);
+    } // for
+  } // for
+}
+
+void test__f_string_dynamic_strip_null_range__parameter_checking(void **state) {
+
+  const f_range_t range = f_range_t_initialize;
+
+  {
+    const f_status_t status = f_string_dynamic_strip_null_range(range, 0);
+
+    assert_int_equal(status, F_status_set_error(F_parameter));
+  }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_0/f_string/tests/unit/c/test-string-dynamic_strip_null_range.h b/level_0/f_string/tests/unit/c/test-string-dynamic_strip_null_range.h
new file mode 100644 (file)
index 0000000..8e73f93
--- /dev/null
@@ -0,0 +1,48 @@
+/**
+ * FLL - Level 0
+ *
+ * Project: String
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the array types in the type project.
+ */
+#ifndef _TEST__F_dynamic_strip_null_range_h
+#define _TEST__F_dynamic_strip_null_range_h
+
+/**
+ * Test that the function returns F_data_not because the buffer is empty.
+ *
+ * @see f_string_dynamic_strip_null_range()
+ */
+extern void test__f_string_dynamic_strip_null_range__returns_data_not(void **state);
+
+/**
+ * Test that the function returns F_data_not_eos because range stops after buffer ends (range.stop >= buffer.used).
+ *
+ * @see f_string_dynamic_strip_null_range()
+ */
+extern void test__f_string_dynamic_strip_null_range__returns_data_not_eos(void **state);
+
+/**
+ * Test that the function returns F_data_not_stop because range is an empty range (range.start > range.stop).
+ *
+ * @see f_string_dynamic_strip_null_range()
+ */
+extern void test__f_string_dynamic_strip_null_range__returns_data_not_stop(void **state);
+
+/**
+ * Test that the function works.
+ *
+ * @see f_string_dynamic_strip_null_range()
+ */
+extern void test__f_string_dynamic_strip_null_range__works(void **state);
+
+/**
+ * Test that the function correctly fails on invalid parameter.
+ *
+ * @see f_string_dynamic_strip_null_range()
+ */
+extern void test__f_string_dynamic_strip_null_range__parameter_checking(void **state);
+
+#endif // _TEST__F_dynamic_strip_null_range_h
index 048693cfb1be246524e6ffa4f64f7ac9dbc718b9..a162a31cb754fc5fc9995b7e60ac6bac4de034fe 100644 (file)
@@ -72,6 +72,14 @@ int main(void) {
     cmocka_unit_test(test__f_string_dynamic_seek_to__returns_none_stop),
     cmocka_unit_test(test__f_string_dynamic_seek_to__works),
 
+    cmocka_unit_test(test__f_string_dynamic_strip_null__returns_data_not),
+    cmocka_unit_test(test__f_string_dynamic_strip_null__works),
+
+    cmocka_unit_test(test__f_string_dynamic_strip_null_range__returns_data_not),
+    cmocka_unit_test(test__f_string_dynamic_strip_null_range__returns_data_not_eos),
+    cmocka_unit_test(test__f_string_dynamic_strip_null_range__returns_data_not_stop),
+    cmocka_unit_test(test__f_string_dynamic_strip_null_range__works),
+
     cmocka_unit_test(test__f_string_dynamic_terminate__appends_null),
     cmocka_unit_test(test__f_string_dynamic_terminate__doesnt_append_null),
 
@@ -234,6 +242,9 @@ int main(void) {
       cmocka_unit_test(test__f_string_dynamic_seek_line_to__parameter_checking),
       cmocka_unit_test(test__f_string_dynamic_seek_to__parameter_checking),
 
+      cmocka_unit_test(test__f_string_dynamic_strip_null__parameter_checking),
+      cmocka_unit_test(test__f_string_dynamic_strip_null_range__parameter_checking),
+
       cmocka_unit_test(test__f_string_dynamic_terminate__parameter_checking),
       cmocka_unit_test(test__f_string_dynamic_terminate_after__parameter_checking),
 
index aa3441c3de1e6724f44bd7c926352991a451a026..109711d27bc056eae5a33135d9bc2bf60528c583 100644 (file)
@@ -57,6 +57,8 @@
 #include "test-string-dynamic_seek_line.h"
 #include "test-string-dynamic_seek_line_to.h"
 #include "test-string-dynamic_seek_to.h"
+#include "test-string-dynamic_strip_null.h"
+#include "test-string-dynamic_strip_null_range.h"
 #include "test-string-dynamic_terminate.h"
 #include "test-string-dynamic_terminate_after.h"
 #include "test-string-dynamics_append.h"