From 99eeab90315f3391d849bf7d658e27dfbbba4235 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Sat, 19 Sep 2026 17:07:29 -0500 Subject: [PATCH] Progress: Work on basic list combining tests, changing test strategy. The previous strategies that I used were only doing a file of only **Objects** and files of only **Contents**. This worked well for simple things. This ideally better allowed for more isolated unit tests. However, it is easier to write and follow tests of a complete **FSS** file. This means doing both the **Object** and **Content** tests in the same unit test (despite being separate functions). This provides more accurate checks, better testing, and as mentioned easier to write and follow test files. --- level_1/fl_fss/c/fss/basic_list.c | 157 +++++---- level_1/fl_fss/c/private-fss-list.c | 15 +- level_1/fl_fss/c/private-fss.c | 5 +- .../contents/basic_list-combining_read-1.txt | 2 + .../contents/basic_list-combining_read-2.txt | 2 +- .../contents/basic_list-combining_read-3.txt | 2 +- .../contents/basic_list-combining_read-4.txt | 3 +- .../contents/basic_list-combining_read-5.txt | 2 - .../counts/basic_list-combining_read.txt | 5 + .../matches/basic_list-combining_read.txt | 5 + .../objects/basic_list-combining_read.txt | 1 - .../strings/basic_list-combining_read.txt | 2 +- level_1/fl_fss/tests/unit/c/data-fss.c | 59 ++++ level_1/fl_fss/tests/unit/c/data-fss.h | 45 +++ .../unit/c/test-fss-basic_list_content_read.c | 311 ++++++++++-------- .../c/test-fss-extended_list_content_read.c | 3 - level_1/fl_fss/tests/unit/c/test-fss.c | 4 +- 17 files changed, 403 insertions(+), 220 deletions(-) delete mode 100644 level_1/fl_fss/data/tests/contents/basic_list-combining_read-5.txt create mode 100644 level_1/fl_fss/data/tests/counts/basic_list-combining_read.txt create mode 100644 level_1/fl_fss/data/tests/matches/basic_list-combining_read.txt diff --git a/level_1/fl_fss/c/fss/basic_list.c b/level_1/fl_fss/c/fss/basic_list.c index b6044cb88..ba5b46d24 100644 --- a/level_1/fl_fss/c/fss/basic_list.c +++ b/level_1/fl_fss/c/fss/basic_list.c @@ -39,6 +39,7 @@ extern "C" { #define ___fl_flag_do_escape___ 0x1 #define ___fl_flag_has_graph_first___ 0x2 + #define ___fl_flag_has_graph_first_do_escape___ 0x3 #define ___fl_flag_has_delimit_comment___ 0x4 #define ___fl_flag_has_delimit_comment_graph_first___ 0x6 @@ -80,10 +81,11 @@ extern "C" { } if (buffer.string[range->start] == f_fss_slash_s.string[0]) { - slash_first = range->start; + slash_first = range->start++; slash_count = 1; + flag_fl |= ___fl_flag_do_escape___; - for (++range->start; range->start <= range->stop && range->start < buffer.used; ++range->start) { + for (; F_status_is_error_not(state->status) && range->start <= range->stop && range->start < buffer.used; ++range->start) { if (state->interrupt) { state->interrupt((void *) state, 0); @@ -91,34 +93,47 @@ extern "C" { } if (buffer.string[range->start] == f_fss_placeholder_s.string[0]) continue; + + // If any slash has a combining/joiner following it, then there is no escaping at all for that slash and therefore it is not considered an escaping character. + if (f_fss_is_combining_joiner(buffer, *range, state) == F_true) { + flag_fl &= ~___fl_flag_has_graph_first_do_escape___; + slash_count = 0; + + f_fss_skip_past_combining_joiner(buffer, range, state); + + break; + } + + if (F_status_is_error(state->status)) return; if (buffer.string[range->start] != f_fss_slash_s.string[0]) break; ++slash_count; - } // for + } // while + if (F_status_is_error(state->status)) return; if (range->start > range->stop || range->start >= buffer.used) break; + if (!(flag_fl & ___fl_flag_do_escape___)) continue; if (buffer.string[range->start] == f_fss_basic_list_open_s.string[0]) { flag_fl &= ~___fl_flag_has_delimit_comment_graph_first___; ++range->start; - while (range->start <= range->stop && range->start < buffer.used) { + f_fss_skip_past_space(buffer, range, state); - if (state->interrupt) { - state->interrupt((void *) state, 0); - if (F_status_set_fine(state->status) == F_interrupt) break; - } + // The skip space returns F_complete_not_utf_start with error bit set on combining/joiner. + if (F_status_set_fine(state->status) == F_complete_not_utf_start) { + flag_fl &= ~___fl_flag_has_graph_first_do_escape___; + slash_count = 0; - if (buffer.string[range->start] == f_fss_eol_s.string[0]) break; - if (f_fss_is_space(buffer, *range, state) == F_false) break; + f_fss_skip_past_combining_joiner(buffer, range, state); - state->status = f_utf_buffer_increment(buffer, range, 1); - if (F_status_is_error(state->status)) break; - } // while + continue; + } + if (F_status_is_error(state->status) || state->status == F_data_not) return; if (range->start > range->stop || range->start >= buffer.used) break; - if (buffer.string[range->start] == f_fss_eol_s.string[0]) { + if (state->status == F_okay_eol) { start = range->start; range->start = slash_first; @@ -159,8 +174,15 @@ extern "C" { flag_fl |= ___fl_flag_has_graph_first___; range->start = start + 1; } + else { + flag_fl &= ~___fl_flag_do_escape___; + slash_count = 0; + } } + + // TODO: Resume here. else if ((flag_fl & ___fl_flag_has_graph_first___) && buffer.string[range->start] == f_fss_comment_s.string[0]) { + // TODO: check combining/joiner. flag_fl &= ___fl_flag_has_delimit_comment___; comment_delimit = slash_first; ++range->start; @@ -173,7 +195,9 @@ extern "C" { ++range->start; flag_fl &= ~___fl_flag_has_delimit_comment_graph_first___; - while (range->start <= range->stop && range->start < buffer.used) { + // TODO: check combining/joiner. + + while (range->start <= range->stop && range->start < buffer.used) { // TODO: replace with seek to eol? if (state->interrupt) { state->interrupt((void *) state, 0); @@ -194,7 +218,6 @@ extern "C" { if (buffer.string[range->start] == f_fss_eol_s.string[0]) { if (newline_last == found->array[found->used].start && buffer.string[found->array[found->used].start] != f_fss_eol_s.string[0]) { range->start = newline_last; - state->status = F_fss_found_content_not; return; @@ -223,6 +246,7 @@ extern "C" { } if ((flag_fl & ___fl_flag_has_graph_first___) && buffer.string[range->start] == f_fss_comment_s.string[0]) { + // TODO: check combining/joiner. // The newline_last is initialized to the range->start, which may not actually be a new line. if (buffer.string[newline_last] == f_string_eol_s.string[0]) { @@ -351,7 +375,7 @@ extern "C" { const f_number_unsigned_t destination_used = destination->used; - uint8_t flag = prepend ? ___fl_flag_do_prepend___ : 0x0; + uint8_t flag_fl = prepend ? ___fl_flag_do_prepend___ : 0x0; uint8_t width = 0; f_number_unsigned_t i = 0; @@ -366,50 +390,50 @@ extern "C" { if (F_status_set_fine(state->status) == F_interrupt) break; } - if (flag & ___fl_flag_is_combining___) { + if (flag_fl & ___fl_flag_is_combining___) { f_fss_skip_past_delimit(content, range, state); if (F_status_is_error(state->status)) break; if (f_fss_is_combining(content, *range, state) != F_true) { if (F_status_is_error(state->status)) break; - flag &= ~___fl_flag_is_combining___; + flag_fl &= ~___fl_flag_is_combining___; } } - if (flag & ___fl_flag_is_joinerd___) { + if (flag_fl & ___fl_flag_is_joinerd___) { f_fss_skip_past_delimit(content, range, state); if (F_status_is_error(state->status)) break; if (f_fss_is_joiner(content, *range, state) == F_true) { - flag |= ___fl_flag_is_joiner___; - flag &= ~___fl_flag_is_joined___; + flag_fl |= ___fl_flag_is_joiner___; + flag_fl &= ~___fl_flag_is_joined___; } else { if (F_status_is_error(state->status)) break; - if (flag & ___fl_flag_is_joiner___) { - flag |= ___fl_flag_is_joined___; - flag &= ~___fl_flag_is_joiner___; + if (flag_fl & ___fl_flag_is_joiner___) { + flag_fl |= ___fl_flag_is_joined___; + flag_fl &= ~___fl_flag_is_joiner___; } else { - flag &= ~___fl_flag_is_joined___; + flag_fl &= ~___fl_flag_is_joined___; } } } - if (content.string[range->start] == f_fss_slash_s.string[0] && !(flag & ___fl_flag_is_comment___)) { + if (content.string[range->start] == f_fss_slash_s.string[0] && !(flag_fl & ___fl_flag_is_comment___)) { slash_count = 1; - if (flag & ___fl_flag_do_prepend___) { + if (flag_fl & ___fl_flag_do_prepend___) { state->status = f_string_dynamic_append(*prepend, destination); if (F_status_is_error(state->status)) break; - flag &= ~___fl_flag_do_prepend___; + flag_fl &= ~___fl_flag_do_prepend___; } destination->string[destination->used++] = content.string[range->start]; - flag |= ___fl_flag_has_graph___; + flag_fl |= ___fl_flag_has_graph___; for (++range->start; range->start <= range->stop && range->start < content.used; ++range->start) { @@ -437,6 +461,17 @@ extern "C" { start = range->start++; f_fss_skip_past_space(content, range, state); + +/* + if (F_status_set_fine(state->status) == F_complete_not_utf_start) { + flag_fl &= ~___fl_flag_has_graph_first_do_escape___; + slash_count = 0; + + f_fss_skip_past_combining_joiner(buffer, range, state); + + continue; + }*/ + if (F_status_is_error(state->status)) break; if (state->status == F_okay_eol || range->start >= content.used || range->start > range->stop) { @@ -469,19 +504,29 @@ extern "C" { continue; } } - else if (content.string[range->start] == f_fss_basic_list_open_s.string[0] && !(flag & ___fl_flag_is_comment___)) { + else if (content.string[range->start] == f_fss_basic_list_open_s.string[0] && !(flag_fl & ___fl_flag_is_comment___)) { start = range->start++; - if (flag & ___fl_flag_do_prepend___) { + if (flag_fl & ___fl_flag_do_prepend___) { state->status = f_string_dynamic_append(*prepend, destination); if (F_status_is_error(state->status)) break; - flag &= ~___fl_flag_do_prepend___; + flag_fl &= ~___fl_flag_do_prepend___; } - flag |= ___fl_flag_has_graph___; + flag_fl |= ___fl_flag_has_graph___; + + f_fss_skip_past_space(content, range, state); // TODO: destination->string[destination->used++] = f_fss_slash_s.string[0]; don't skip entirely, also write! Do this for all before continuing based on the "start" position above. +/* + if (F_status_set_fine(state->status) == F_complete_not_utf_start) { + flag_fl &= ~___fl_flag_has_graph_first_do_escape___; + slash_count = 0; + + f_fss_skip_past_combining_joiner(buffer, range, state); + + continue; // TODO: see todo's above and also repeat for the other cases in this file. + }*/ - f_fss_skip_past_space(content, range, state); if (F_status_is_error(state->status)) break; if (state->status == F_okay_eol || range->start >= content.used || range->start > range->stop) { @@ -509,11 +554,11 @@ extern "C" { continue; } - else if (content.string[range->start] == f_fss_comment_s.string[0] && !(flag & ___fl_flag_has_graph___)) { - flag |= ___fl_flag_is_comment___; + else if (content.string[range->start] == f_fss_comment_s.string[0] && !(flag_fl & ___fl_flag_has_graph___)) { + flag_fl |= ___fl_flag_is_comment___; } else if (content.string[range->start] == f_fss_eol_s.string[0]) { - flag = 0x0; + flag_fl = 0x0; } else if (f_fss_is_graph(content, *range, state) == F_false) { if (F_status_is_error(state->status)) break; @@ -525,10 +570,10 @@ extern "C" { if (state->status == F_okay) { if (f_fss_is_combining_joiner(content, *range, state)) { if (state->status == F_combarudoo) { - flag |= ___fl_flag_is_combining_graph___; + flag_fl |= ___fl_flag_is_combining_graph___; } else if (state->status == F_bound) { - flag |= ___fl_flag_is_joiner_graph___; + flag_fl |= ___fl_flag_is_joiner_graph___; } } } @@ -538,19 +583,19 @@ extern "C" { range->start = previous; } else { - flag |= ___fl_flag_has_graph___; + flag_fl |= ___fl_flag_has_graph___; } if (content.string[range->start] != f_fss_placeholder_s.string[0]) { - if (flag & ___fl_flag_do_prepend___) { + if (flag_fl & ___fl_flag_do_prepend___) { state->status = f_string_dynamic_append(*prepend, destination); if (F_status_is_error(state->status)) break; - flag &= ~___fl_flag_do_prepend___; + flag_fl &= ~___fl_flag_do_prepend___; } if (content.string[range->start] == f_fss_eol_s.string[0] && prepend) { - flag |= ___fl_flag_do_prepend___; + flag_fl |= ___fl_flag_do_prepend___; } width = macro_f_utf_byte_width(content.string[range->start]); @@ -686,7 +731,7 @@ extern "C" { f_number_unsigned_t previous = 0; f_number_unsigned_t slash_count = 0; - uint8_t flag = 0; + uint8_t flag_fl = 0; uint8_t width = 0; // Find the first graph character. @@ -708,34 +753,34 @@ extern "C" { break; } - if (flag & ___fl_flag_is_combining___) { + if (flag_fl & ___fl_flag_is_combining___) { f_fss_skip_past_delimit(object, range, state); if (F_status_is_error(state->status)) break; if (f_fss_is_combining(object, *range, state) != F_true) { if (F_status_is_error(state->status)) break; - flag &= ~___fl_flag_is_combining___; + flag_fl &= ~___fl_flag_is_combining___; } } - if (flag & ___fl_flag_is_joinerd___) { + if (flag_fl & ___fl_flag_is_joinerd___) { f_fss_skip_past_delimit(object, range, state); if (F_status_is_error(state->status)) break; if (f_fss_is_joiner(object, *range, state) == F_true) { - flag |= ___fl_flag_is_joiner___; - flag &= ~___fl_flag_is_joined___; + flag_fl |= ___fl_flag_is_joiner___; + flag_fl &= ~___fl_flag_is_joined___; } else { if (F_status_is_error(state->status)) break; - if (flag & ___fl_flag_is_joiner___) { - flag |= ___fl_flag_is_joined___; - flag &= ~___fl_flag_is_joiner___; + if (flag_fl & ___fl_flag_is_joiner___) { + flag_fl |= ___fl_flag_is_joined___; + flag_fl &= ~___fl_flag_is_joiner___; } else { - flag &= ~___fl_flag_is_joined___; + flag_fl &= ~___fl_flag_is_joined___; } } } @@ -750,10 +795,10 @@ extern "C" { if (state->status == F_okay) { if (f_fss_is_combining_joiner(object, *range, state)) { if (state->status == F_combarudoo) { - flag |= ___fl_flag_is_combining_graph___; + flag_fl |= ___fl_flag_is_combining_graph___; } else if (state->status == F_bound) { - flag |= ___fl_flag_is_joiner_graph___; + flag_fl |= ___fl_flag_is_joiner_graph___; } } } diff --git a/level_1/fl_fss/c/private-fss-list.c b/level_1/fl_fss/c/private-fss-list.c index 9a0918a3d..9940293e5 100644 --- a/level_1/fl_fss/c/private-fss-list.c +++ b/level_1/fl_fss/c/private-fss-list.c @@ -11,6 +11,7 @@ extern "C" { f_fss_skip_past_space(buffer, range, state); if (F_status_is_error(state->status) || state->status == F_data_not) return; + // Return found nothing if this line only contains white space and delimit placeholders. if (state->status == F_okay_eol) { // Move the start position to after the EOL. @@ -26,16 +27,6 @@ extern "C" { return; } - // Return found nothing if this line only contains white space and delimit placeholders. - if (state->status == F_okay_eol) { - - // Move the start position to after the EOL. - ++range->start; - state->status = F_fss_found_object_not; - - return; - } - const f_number_unsigned_t begin = range->start; // Ignore all comment lines. @@ -176,6 +167,7 @@ extern "C" { if (F_status_is_error_not(state->status)) { if (f_fss_is_combining_joiner(buffer, *range, state) == F_true) { + flag_fl &= ~___fl_flag_do_escape___; slash_count = 0; f_fss_skip_past_combining_joiner(buffer, range, state); @@ -219,7 +211,7 @@ extern "C" { } if (slash_count % 2 == 0) { - while (slash_count > 0) { + while (slash_count) { if (buffer.string[range->start] == f_fss_slash_s.string[0]) { if (slash_count % 2 == 1) { @@ -275,6 +267,7 @@ extern "C" { if (F_status_is_error_not(state->status)) { if (f_fss_is_combining_joiner(buffer, *range, state) == F_true) { + flag_fl &= ~___fl_flag_do_escape___; slash_count = 0; f_fss_skip_past_combining_joiner(buffer, range, state); diff --git a/level_1/fl_fss/c/private-fss.c b/level_1/fl_fss/c/private-fss.c index 1017af231..2b49539c4 100644 --- a/level_1/fl_fss/c/private-fss.c +++ b/level_1/fl_fss/c/private-fss.c @@ -115,7 +115,7 @@ extern "C" { } if (buffer.string[range->start] == f_fss_placeholder_s.string[0]) { - state->status = f_utf_buffer_increment(buffer, range, 1); + ++range->start; continue; } @@ -254,8 +254,7 @@ extern "C" { } if (buffer.string[range->start] == f_fss_placeholder_s.string[0]) { - state->status = f_utf_buffer_increment(buffer, range, 1); - if (F_status_is_error(state->status)) return; + ++range->start; continue; } diff --git a/level_1/fl_fss/data/tests/contents/basic_list-combining_read-1.txt b/level_1/fl_fss/data/tests/contents/basic_list-combining_read-1.txt index 311e0a561..177a9a6f7 100644 --- a/level_1/fl_fss/data/tests/contents/basic_list-combining_read-1.txt +++ b/level_1/fl_fss/data/tests/contents/basic_list-combining_read-1.txt @@ -1 +1,3 @@ is_second and content 2. + ́: + does not have ́ content 3. diff --git a/level_1/fl_fss/data/tests/contents/basic_list-combining_read-2.txt b/level_1/fl_fss/data/tests/contents/basic_list-combining_read-2.txt index 652a208a4..96487d57a 100644 --- a/level_1/fl_fss/data/tests/contents/basic_list-combining_read-2.txt +++ b/level_1/fl_fss/data/tests/contents/basic_list-combining_read-2.txt @@ -1 +1 @@ - has ́ content 3. + has ͜no_space content 4. diff --git a/level_1/fl_fss/data/tests/contents/basic_list-combining_read-3.txt b/level_1/fl_fss/data/tests/contents/basic_list-combining_read-3.txt index 96487d57a..78c611949 100644 --- a/level_1/fl_fss/data/tests/contents/basic_list-combining_read-3.txt +++ b/level_1/fl_fss/data/tests/contents/basic_list-combining_read-3.txt @@ -1 +1 @@ - has ͜no_space content 4. + content 5. diff --git a/level_1/fl_fss/data/tests/contents/basic_list-combining_read-4.txt b/level_1/fl_fss/data/tests/contents/basic_list-combining_read-4.txt index 78c611949..5e7418a06 100644 --- a/level_1/fl_fss/data/tests/contents/basic_list-combining_read-4.txt +++ b/level_1/fl_fss/data/tests/contents/basic_list-combining_read-4.txt @@ -1 +1,2 @@ - content 5. + sixtẖ̚ is content 6. + not a valid list:́ diff --git a/level_1/fl_fss/data/tests/contents/basic_list-combining_read-5.txt b/level_1/fl_fss/data/tests/contents/basic_list-combining_read-5.txt deleted file mode 100644 index 5e7418a06..000000000 --- a/level_1/fl_fss/data/tests/contents/basic_list-combining_read-5.txt +++ /dev/null @@ -1,2 +0,0 @@ - sixtẖ̚ is content 6. - not a valid list:́ diff --git a/level_1/fl_fss/data/tests/counts/basic_list-combining_read.txt b/level_1/fl_fss/data/tests/counts/basic_list-combining_read.txt new file mode 100644 index 000000000..9f145d81c --- /dev/null +++ b/level_1/fl_fss/data/tests/counts/basic_list-combining_read.txt @@ -0,0 +1,5 @@ +1 +3 +1 +1 +1 diff --git a/level_1/fl_fss/data/tests/matches/basic_list-combining_read.txt b/level_1/fl_fss/data/tests/matches/basic_list-combining_read.txt new file mode 100644 index 000000000..3f22f14bf --- /dev/null +++ b/level_1/fl_fss/data/tests/matches/basic_list-combining_read.txt @@ -0,0 +1,5 @@ +2 +2 +2 +2 +2 diff --git a/level_1/fl_fss/data/tests/objects/basic_list-combining_read.txt b/level_1/fl_fss/data/tests/objects/basic_list-combining_read.txt index d2132bf51..b540243f9 100644 --- a/level_1/fl_fss/data/tests/objects/basic_list-combining_read.txt +++ b/level_1/fl_fss/data/tests/objects/basic_list-combining_read.txt @@ -1,6 +1,5 @@ first valid. is_second and does not have embedded new line. - ́ fourth ͜no_space fifth is valid. sixtẖ̚ is valid with two combiners. diff --git a/level_1/fl_fss/data/tests/strings/basic_list-combining_read.txt b/level_1/fl_fss/data/tests/strings/basic_list-combining_read.txt index 6f47d5cfb..5b9125828 100644 --- a/level_1/fl_fss/data/tests/strings/basic_list-combining_read.txt +++ b/level_1/fl_fss/data/tests/strings/basic_list-combining_read.txt @@ -3,7 +3,7 @@ first valid.: is_second and does not have embedded new line.: is_second and content 2. ́: - has ́ content 3. + does not have ́ content 3. fourth ͜no_space: has ͜no_space content 4. fifth is valid.: diff --git a/level_1/fl_fss/tests/unit/c/data-fss.c b/level_1/fl_fss/tests/unit/c/data-fss.c index ea4d35db4..cd91e26d1 100644 --- a/level_1/fl_fss/tests/unit/c/data-fss.c +++ b/level_1/fl_fss/tests/unit/c/data-fss.c @@ -26,6 +26,65 @@ FILE *data__file_open__named_at(const f_string_t set, const f_string_t name, con return fopen(path, "r"); } +f_status_t data__file_load_buffer(FILE * const file, f_string_dynamic_t * const buffer) { + + if (!buffer) { + return F_status_set_error(F_parameter); + } + + f_status_t status = F_okay; + ssize_t result = 0; + size_t max = 0; + char *lines = 0; + f_string_static_t temporary = f_string_static_t_initialize; + + buffer->used = 0; + + for (int i = 0; ; ++i, max = 255) { + + result = getline(&lines, &max, file); + if (result <= 0) break; + + temporary.string = lines; + temporary.used = (f_number_unsigned_t) result; + temporary.size = temporary.used; + + status = f_string_dynamic_append_nulless(temporary, buffer); + if (F_status_is_error(status)) break; + + if (lines) free(lines); + + lines = 0; + } // for + + if (F_status_is_error_not(status)) { + status = f_string_dynamic_terminate_after(buffer); + } + + if (lines) free(lines); + + return status; +} + +f_status_t data__extract_from_source(const f_string_static_t source, const f_range_t range, f_string_dynamic_t * const destination) { + + if (!destination) { + return F_status_set_error(F_parameter); + } + + f_status_t status = F_okay; + + destination->used = 0; + + status = f_string_dynamic_partial_append_nulless(source, range, destination); + + if (F_status_is_error_not(status)) { + status = f_string_dynamic_terminate_after(destination); + } + + return status; +} + #ifdef __cplusplus } // extern "C" #endif diff --git a/level_1/fl_fss/tests/unit/c/data-fss.h b/level_1/fl_fss/tests/unit/c/data-fss.h index 15a5ee84f..f3ea807ce 100644 --- a/level_1/fl_fss/tests/unit/c/data-fss.h +++ b/level_1/fl_fss/tests/unit/c/data-fss.h @@ -74,6 +74,51 @@ extern FILE *data__file_open__named(const f_string_t set, const f_string_t name, */ extern FILE *data__file_open__named_at(const f_string_t set, const f_string_t name, const f_string_t context, const uint16_t at); +/** + * Append file into buffer. + * + * @param file + * The file, which must already be open. + * @param buffer + * The buffer to append to. + * The buffer.used is set to 0 on start, unless NULL. + * + * @return + * F_okay on success. + * + * F_parameter (with error bit) if a parameter is invalid. + * + * Errors (with error bit) from: f_string_dynamic_append_nulless(). + * Errors (with error bit) from: f_string_dynamic_terminate_after(). + * + * @see f_string_dynamic_append() + * @see f_string_dynamic_terminate_after() + */ +extern f_status_t data__file_load_buffer(FILE * const file, f_string_dynamic_t * const buffer); + +/** + * Extract the given string and range from the source buffer. + * + * The removes NULLs when extracting and ensures the string is NULL terminated. + * + * @param source + * The buffer to read from. + * @param range + * The range within the buffer to extract. + * @param destination + * The extracted string. + * The destination.used is set to 0 on start, unless NULL. + * + * @return + * F_okay on success. + * + * F_parameter (with error bit) if a parameter is invalid. + * + * Errors (with error bit) from: f_string_dynamic_partial_append_nulless(). + * Errors (with error bit) from: f_string_dynamic_terminate_after(). + */ +extern f_status_t data__extract_from_source(const f_string_static_t source, const f_range_t range, f_string_dynamic_t * const destination); + #ifdef __cplusplus } // extern "C" #endif diff --git a/level_1/fl_fss/tests/unit/c/test-fss-basic_list_content_read.c b/level_1/fl_fss/tests/unit/c/test-fss-basic_list_content_read.c index 091134979..ea84bad35 100644 --- a/level_1/fl_fss/tests/unit/c/test-fss-basic_list_content_read.c +++ b/level_1/fl_fss/tests/unit/c/test-fss-basic_list_content_read.c @@ -334,7 +334,9 @@ void test__fl_fss_basic_list_content_read__works_using_combining(void **void_sta { // Note: These files are required to have the same number of lines and each line should probably be at max 255 characters. + FILE *file_counts = data__file_open__named("counts", "basic_list", "combining_read"); FILE *file_matches = data__file_open__named("matches", "basic_list", "combining_read"); + FILE *file_objects = data__file_open__named("objects", "basic_list", "combining_read"); FILE *file_strings = data__file_open__named("strings", "basic_list", "combining_read"); FILE *file_contents[] = { @@ -343,92 +345,129 @@ void test__fl_fss_basic_list_content_read__works_using_combining(void **void_sta data__file_open__named_at("contents", "basic_list", "combining_read", 2), data__file_open__named_at("contents", "basic_list", "combining_read", 3), data__file_open__named_at("contents", "basic_list", "combining_read", 4), - data__file_open__named_at("contents", "basic_list", "combining_read", 5), }; + assert_non_null(file_counts); assert_non_null(file_matches); + assert_non_null(file_objects); assert_non_null(file_strings); assert_non_null(file_contents[0]); assert_non_null(file_contents[1]); assert_non_null(file_contents[2]); assert_non_null(file_contents[3]); assert_non_null(file_contents[4]); - assert_non_null(file_contents[5]); + const uint8_t sets_total = 5; + + int counts = 0; int matches = 0; size_t max = 0; - char *line_matches = 0; - char *line_string = 0; - char *line_content[] = { - 0, - 0, - 0, - 0, - 0, - 0, - }; ssize_t result = 0; - const uint8_t total_content = 6; - f_string_static_t buffer_string = f_string_static_t_initialize; + char *line_counts = 0; + char *line_matches = 0; + char *line_object = 0; - f_state_t state = f_state_t_initialize; f_range_t range = f_range_t_initialize; f_range_t found_object = f_range_t_initialize; - f_ranges_t found = f_ranges_t_initialize; + f_ranges_t found_content = f_ranges_t_initialize; f_ranges_t comments = f_ranges_t_initialize; + + f_state_t state = f_state_t_initialize; + f_status_t status_object = F_okay; f_uint8s_t quotes = f_uint8s_t_initialize; f_number_unsigneds_t delimits = f_number_unsigneds_t_initialize; - f_string_dynamic_t result_string = f_string_dynamic_t_initialize; - f_string_dynamic_t delimit_string = f_string_dynamic_t_initialize; - f_status_t status_object = F_okay; - for (f_number_unsigned_t line = 0; ; ++line) { + f_string_dynamic_t set_delimit = f_string_dynamic_t_initialize; + f_string_dynamic_t set_result = f_string_dynamic_t_initialize; + f_string_dynamic_t set_strings = f_string_dynamic_t_initialize; - max = 255; + f_string_dynamic_t set_contents[] = { + macro_f_string_dynamic_t_initialize_2(0, 0), + macro_f_string_dynamic_t_initialize_2(0, 0), + macro_f_string_dynamic_t_initialize_2(0, 0), + macro_f_string_dynamic_t_initialize_2(0, 0), + macro_f_string_dynamic_t_initialize_2(0, 0), + }; - result = getline(&line_matches, &max, file_matches); - if (result == -1) break; + { + const f_status_t status = data__file_load_buffer(file_strings, &set_strings); - matches = atoi(line_matches); + if (F_status_is_error(status)) { + printf("[ -------> ] --- [00] Failure with data__file_load_buffer() for loading file strings, status=%u has error bit set.\n", status); + } + + assert_true(F_status_is_error_not(status)); + } + + for (uint8_t i = 0; i < sets_total; ++i) { + + const f_status_t status = data__file_load_buffer(file_contents[i], &set_contents[i]); + + if (F_status_is_error(status)) { + printf("[ -------> ] --- [01] Failure with data__file_load_buffer() for loading file contents at %u, status=%u has error bit set.\n", i, status); + } + + assert_true(F_status_is_error_not(state.status)); + } // for + + { + const f_status_t status = f_string_dynamic_append(set_strings, &set_delimit); + + if (status != F_okay) { + printf("[ -------> ] --- [02] Failure with f_string_dynamic_append() for preparing delimit string, status=%u, expected=%u.\n", status, F_okay); + } + + assert_int_equal(status, F_okay); + } + + range.start = 0; + range.stop = set_strings.used - 1; + + for (f_number_unsigned_t set = 0; set < sets_total; ++set) { max = 255; - result = getline(&line_string, &max, file_strings); - if (result == -1) break; + result = getline(&line_object, &max, file_objects); - buffer_string.string = line_string; - buffer_string.used = (f_number_unsigned_t) result; - buffer_string.size = buffer_string.used; + if (result < 0) { + printf("[ -------> ] --- [03] Failure with getline() for objects, with set %lu, result is negative.\n", set); + } - for (uint8_t i = 0; i < total_content; ++i) { + assert_true(result >= 0); - max = 255; + // The newline is copied by getline(), and so remove that newline before comparing. + if (result) { + line_object[result - 1] = 0; + } + else { + line_object[0] = 0; + } - result = getline(&line_content[i], &max, file_contents[i]); + max = 255; - // The newline is copied by getline(), and so remove that newline before comparing. - if (result > 0) { - line_content[i][result - 1] = 0; - } - else { - line_content[i][0] = 0; - } - } // for + result = getline(&line_matches, &max, file_matches); + + if (result < 0) { + printf("[ -------> ] --- [04] Failure with getline() for matches, with set %lu, result is negative.\n", set); + } + + assert_true(result >= 0); + + matches = atoi(line_matches); - state.status = F_none; - range.start = 0; - range.stop = buffer_string.used - 1; found_object.start = 1; found_object.stop = 0; + state.status = F_none; - fl_fss_basic_list_object_read(buffer_string, &range, &found_object, &delimits, &state); + fl_fss_basic_list_object_read(set_strings, &range, &found_object, &delimits, &state); if (matches) { + // When matches is 2, then this matches both object and content. if (matches == 2) { if (!(state.status == F_fss_found_object)) { - printf("[ -------> ] --- [00] Failure with fl_fss_basic_list_object_read(), with line %lu, matches=%d, status=%u, expected %u.\n", line, matches, state.status, F_fss_found_object); + printf("[ -------> ] --- [05] Failure with fl_fss_basic_list_object_read(), with set %lu, matches=%d, status=%u, expected %u.\n", set, matches, state.status, F_fss_found_object); } assert_true(state.status == F_fss_found_object); @@ -437,7 +476,7 @@ void test__fl_fss_basic_list_content_read__works_using_combining(void **void_sta // When matches is 1, then this matches only object. else { if (!(state.status == F_fss_found_object_content_not)) { - printf("[ -------> ] --- [01] Failure with fl_fss_basic_list_object_read(), with line %lu, matches=%d, status=%u, expected %u.\n", line, matches, state.status, F_fss_found_object_content_not); + printf("[ -------> ] --- [06] Failure with fl_fss_basic_list_object_read(), with set %lu, matches=%d, status=%u, expected %u.\n", set, matches, state.status, F_fss_found_object_content_not); } assert_true(state.status == F_fss_found_object_content_not); @@ -445,7 +484,7 @@ void test__fl_fss_basic_list_content_read__works_using_combining(void **void_sta } else { if (!(state.status == F_fss_found_object_not)) { - printf("[ -------> ] --- [02] Failure with with fl_fss_basic_list_object_read(), line %lu, matches=%d, status=%u, expected %u.\n", line, matches, state.status, F_fss_found_object_not); + printf("[ -------> ] --- [07] Failure with with fl_fss_basic_list_object_read(), set %lu, matches=%d, status=%u, expected %u.\n", set, matches, state.status, F_fss_found_object_not); } assert_true(state.status == F_fss_found_object_not); @@ -455,148 +494,144 @@ void test__fl_fss_basic_list_content_read__works_using_combining(void **void_sta state.status = F_none; if (status_object == F_fss_found_object) { - fl_fss_basic_list_content_read(buffer_string, &range, &found, &delimits, &comments, &state); - - if (!(state.status == F_fss_found_content || state.status == F_data_not)) { - printf("[ -------> ] --- [03] Failure with fl_fss_basic_list_content_read(), with line %lu, status=%u, expected %u or %u.\n", line, state.status, F_fss_found_content, F_data_not); - } - assert_true(state.status == F_fss_found_content || state.status == F_data_not); + // The Object had to be read before getting to the Content, so test it as well. + { + const f_status_t status = data__extract_from_source(set_strings, found_object, &set_result); - if (state.status == F_fss_found_content) { - if (!found.used) { - printf("[ -------> ] --- [04] Failure with fl_fss_basic_list_content_read(), with line %lu, expected found.used > 0.\n", line); + if (F_status_is_error(status)) { + printf("[ -------> ] --- [14] Failure with data__extract_from_source() for extract object, with set %lu, status=%u has error bit set.\n", set, status); } - assert_true(found.used); - - if (found.used <= (f_number_unsigned_t) total_content) { - printf("[ -------> ] --- [05] Failure with fl_fss_basic_list_content_read(), with line %lu, expected found.used (%lu) <= total_conent (%lu).\n", line, found.used, (f_number_unsigned_t) total_content); - } + assert_true(F_status_is_error_not(status)); + } - assert_true(found.used <= (f_number_unsigned_t) total_content); + if (strcmp(set_result.string, line_object)) { + printf("[ -------> ] --- [09] Failure with set %lu, object strings do not match.\n", set); + } - { - const f_status_t status = f_string_dynamic_append(buffer_string, &delimit_string); + assert_string_equal(set_result.string, line_object); - if (status != F_okay) { - printf("[ -------> ] --- [06] Failure with f_string_dynamic_append(), with line %lu, status=%u, expected=%u.\n", line, status, F_okay); - } + max = 255; - assert_int_equal(status, F_okay); - } + result = getline(&line_counts, &max, file_counts); - state.status = F_none; + if (result < 0) { + printf("[ -------> ] --- [10] Failure with getline() for counts, with set %lu, result is negative.\n", set); + } - f_fss_apply_delimit(delimits, &delimit_string, &state); + assert_true(result >= 0); - if (state.status != F_okay) { - printf("[ -------> ] --- [07] Failure with f_fss_apply_delimit(), with line %lu, status=%u, expected=%u.\n", line, state.status, F_okay); - } + counts = atoi(line_counts); - assert_int_equal(state.status, F_okay); + fl_fss_basic_list_content_read(set_strings, &range, &found_content, &delimits, &comments, &state); - { - uint8_t i = 0; + if (!(state.status == F_fss_found_content || state.status == F_data_not)) { + printf("[ -------> ] --- [11] Failure with fl_fss_basic_list_content_read(), with set %lu, status=%u, expected %u or %u.\n", set, state.status, F_fss_found_content, F_data_not); + } - for (; i < found.used; ++i) { + assert_true(state.status == F_fss_found_content || state.status == F_data_not); - result_string.used = 0; + if (state.status == F_fss_found_content) { + if (!found_content.used) { + printf("[ -------> ] --- [12] Failure with fl_fss_basic_list_content_read(), with set %lu, expected found_content.used (%lu) <> 0.\n", set, found_content.used); + } - { - const f_status_t status = f_string_dynamic_partial_append_nulless(delimit_string, found.array[i], &result_string); + assert_true(found_content.used); - if (!(status == F_okay || status == F_data_not_eos)) { - printf("[ -------> ] --- [08] Failure with f_string_dynamic_partial_append_nulless(), with line %lu, status=%u, expected %u or %u.\n", line, status, F_okay, F_data_not_eos); - } + if (found_content.used != (f_number_unsigned_t) counts) { + printf("[ -------> ] --- [13] Failure with fl_fss_basic_list_content_read(), with set %lu, expected found_content.used (%lu) == %lu.\n", set, found_content.used, (f_number_unsigned_t) counts); + } - assert_true(status == F_okay || status == F_data_not_eos); - } + assert_true(found_content.used == (f_number_unsigned_t) counts); - { - const f_status_t status = f_string_dynamic_terminate_after(&result_string); + state.status = F_none; - if (!(status == F_okay)) { - printf("[ -------> ] --- [09] Failure with f_string_dynamic_terminate_after(), with line %lu, status=%u, expected %u.\n", line, status, F_okay); - } + f_fss_apply_delimit(delimits, &set_delimit, &state); - assert_int_equal(status, F_okay); - } + if (state.status != F_okay) { + printf("[ -------> ] --- [14] Failure with f_fss_apply_delimit(), with set %lu, status=%u, expected=%u.\n", set, state.status, F_okay); + } - if (strcmp(result_string.string, line_content[i])) { - printf("[ -------> ] --- [10] Failure with line %lu, strings do not match.\n", line); - } + assert_int_equal(state.status, F_okay); - assert_string_equal(result_string.string, line_content[i]); - } // for + { + const f_status_t status = data__extract_from_source(set_delimit, found_content.array[0], &set_result); - // All remaining positions in the file need to be a zero length string. - for (; i < total_content; ++i) { - assert_int_equal(line_content[i][0], 0); + if (F_status_is_error(status)) { + printf("[ -------> ] --- [15] Failure with data__extract_from_source() for extract set contents, with set %lu, status=%u has error bit set.\n", set, status); } + + assert_true(F_status_is_error_not(status)); } + + if (strcmp(set_result.string, set_contents[set].string)) { + printf("[ -------> ] --- [16] Failure with set %lu, content strings do not match.\n", set); + } + + assert_string_equal(set_result.string, set_contents[set].string); } else { - assert_true(!found.used); + if (found_content.used) { + printf("[ -------> ] --- [17] Failure with set %lu, should not have any content, but match %lu.\n", set, found_content.used); + } + + assert_true(!found_content.used); } } - if (line_matches) free(line_matches); - if (line_string) free(line_string); - if (result_string.string) free(result_string.string); - if (delimit_string.string) free(delimit_string.string); - if (delimits.array) free(delimits.array); - if (found.array) free(found.array); if (comments.array) free(comments.array); + if (delimits.array) free(delimits.array); + if (found_content.array) free(found_content.array); if (quotes.array) free(quotes.array); - for (uint8_t i = 0; i < total_content; ++i) { - - if (line_content[i]) free(line_content[i]); - - line_content[i] = 0; - } // for + if (line_counts) free(line_counts); + if (line_matches) free(line_matches); + if (line_object) free(line_object); + if (set_result.string) free(set_result.string); - line_matches = 0; - line_string = 0; - result_string.string = 0; - result_string.used = 0; - result_string.size = 0; - delimit_string.string = 0; - delimit_string.used = 0; - delimit_string.size = 0; - delimits.array = 0; - delimits.used = 0; - delimits.size = 0; - found.array = 0; - found.used = 0; - found.size = 0; comments.array = 0; comments.used = 0; comments.size = 0; + delimits.array = 0; + delimits.used = 0; + delimits.size = 0; + found_content.array = 0; + found_content.used = 0; + found_content.size = 0; + line_counts = 0; + line_matches = 0; + line_object = 0; quotes.array = 0; quotes.used = 0; quotes.size = 0; + set_result.string = 0; + set_result.used = 0; + set_result.size = 0; } // for - for (uint8_t i = 0; i < total_content; ++i) { + for (uint8_t i = 0; i < sets_total; ++i) { if (file_contents[i]) fclose(file_contents[i]); - if (line_content[i]) free(line_content[i]); - - line_content[i] = 0; + if (set_contents[i].string) free(set_contents[i].string); } // for + if (line_counts) free(line_counts); + if (line_matches) free(line_matches); + if (line_object) free(line_object); + if (set_delimit.string) free(set_delimit.string); + if (set_result.string) free(set_result.string); + if (set_strings.string) free(set_strings.string); + + if (file_counts) fclose(file_counts); + if (file_matches) fclose(file_matches); + if (file_objects) fclose(file_objects); if (file_strings) fclose(file_strings); - if (delimits.array) free(delimits.array); - if (found.array) free(found.array); if (comments.array) free(comments.array); + if (delimits.array) free(delimits.array); + if (found_content.array) free(found_content.array); if (quotes.array) free(quotes.array); - if (line_matches) free(line_matches); - if (line_string) free(line_string); - if (result_string.string) free(result_string.string); - if (delimit_string.string) free(delimit_string.string); } } diff --git a/level_1/fl_fss/tests/unit/c/test-fss-extended_list_content_read.c b/level_1/fl_fss/tests/unit/c/test-fss-extended_list_content_read.c index c2095647e..85118934b 100644 --- a/level_1/fl_fss/tests/unit/c/test-fss-extended_list_content_read.c +++ b/level_1/fl_fss/tests/unit/c/test-fss-extended_list_content_read.c @@ -532,9 +532,6 @@ void test__fl_fss_extended_list_content_read__works_using_combining(void **void_ if (result > 0) { line_content[i][result - 1] = 0; } - else { - line_content[i][0] = 0; - } } // or state.status = F_none; diff --git a/level_1/fl_fss/tests/unit/c/test-fss.c b/level_1/fl_fss/tests/unit/c/test-fss.c index 2c9b60473..105b98330 100644 --- a/level_1/fl_fss/tests/unit/c/test-fss.c +++ b/level_1/fl_fss/tests/unit/c/test-fss.c @@ -35,9 +35,9 @@ int main(void) { cmocka_unit_test(test__fl_fss_basic_list_object_write__returns_data_not), cmocka_unit_test(test__fl_fss_basic_list_content_read__works), - //cmocka_unit_test(test__fl_fss_basic_list_content_read__works_using_combining), + cmocka_unit_test(test__fl_fss_basic_list_content_read__works_using_combining), cmocka_unit_test(test__fl_fss_basic_list_object_read__works), - //cmocka_unit_test(test__fl_fss_basic_list_object_read__works_using_combining), + cmocka_unit_test(test__fl_fss_basic_list_object_read__works_using_combining), cmocka_unit_test(test__fl_fss_embedded_list_content_read__returns_data_not), cmocka_unit_test(test__fl_fss_embedded_list_content_write__returns_data_not), -- 2.52.0