From 986ce6e71e150f385896d489b89e72d3c2e42f28 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Tue, 16 Jan 2024 08:22:03 -0600 Subject: [PATCH] Feature: Add f_string_dynamic_strip_null() and f_string_dynamic_strip_null_range(). 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 | 99 ++++++++++ level_0/f_string/c/string/dynamic.h | 46 +++++ level_0/f_string/data/build/settings-tests | 1 + .../tests/unit/c/test-string-dynamic_strip_null.c | 141 ++++++++++++++ .../tests/unit/c/test-string-dynamic_strip_null.h | 34 ++++ .../unit/c/test-string-dynamic_strip_null_range.c | 213 +++++++++++++++++++++ .../unit/c/test-string-dynamic_strip_null_range.h | 48 +++++ level_0/f_string/tests/unit/c/test-string.c | 11 ++ level_0/f_string/tests/unit/c/test-string.h | 2 + 9 files changed, 595 insertions(+) create mode 100644 level_0/f_string/tests/unit/c/test-string-dynamic_strip_null.c create mode 100644 level_0/f_string/tests/unit/c/test-string-dynamic_strip_null.h create mode 100644 level_0/f_string/tests/unit/c/test-string-dynamic_strip_null_range.c create mode 100644 level_0/f_string/tests/unit/c/test-string-dynamic_strip_null_range.h diff --git a/level_0/f_string/c/string/dynamic.c b/level_0/f_string/c/string/dynamic.c index 31f95cb..11acd72 100644 --- a/level_0/f_string/c/string/dynamic.c +++ b/level_0/f_string/c/string/dynamic.c @@ -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_ diff --git a/level_0/f_string/c/string/dynamic.h b/level_0/f_string/c/string/dynamic.h index 29ba25e..d097ab8 100644 --- a/level_0/f_string/c/string/dynamic.h +++ b/level_0/f_string/c/string/dynamic.h @@ -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. diff --git a/level_0/f_string/data/build/settings-tests b/level_0/f_string/data/build/settings-tests index 0bca0f8..9ff452d 100644 --- a/level_0/f_string/data/build/settings-tests +++ b/level_0/f_string/data/build/settings-tests @@ -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 index 0000000..3e5eac8 --- /dev/null +++ b/level_0/f_string/tests/unit/c/test-string-dynamic_strip_null.c @@ -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 index 0000000..35d05d5 --- /dev/null +++ b/level_0/f_string/tests/unit/c/test-string-dynamic_strip_null.h @@ -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 index 0000000..180b319 --- /dev/null +++ b/level_0/f_string/tests/unit/c/test-string-dynamic_strip_null_range.c @@ -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 index 0000000..8e73f93 --- /dev/null +++ b/level_0/f_string/tests/unit/c/test-string-dynamic_strip_null_range.h @@ -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 diff --git a/level_0/f_string/tests/unit/c/test-string.c b/level_0/f_string/tests/unit/c/test-string.c index 048693c..a162a31 100644 --- a/level_0/f_string/tests/unit/c/test-string.c +++ b/level_0/f_string/tests/unit/c/test-string.c @@ -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), diff --git a/level_0/f_string/tests/unit/c/test-string.h b/level_0/f_string/tests/unit/c/test-string.h index aa3441c..109711d 100644 --- a/level_0/f_string/tests/unit/c/test-string.h +++ b/level_0/f_string/tests/unit/c/test-string.h @@ -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" -- 1.8.3.1