]> Kevux Git Server - fll/commitdiff
Progress: Set up the initial structure for the remaining read tests for combining...
authorKevin Day <Kevin@kevux.org>
Sun, 13 Sep 2026 01:43:59 +0000 (20:43 -0500)
committerKevin Day <Kevin@kevux.org>
Sun, 13 Sep 2026 01:43:59 +0000 (20:43 -0500)
It seems that editors make it difficult to add and manipulate combining characters.
It is possible my test files have lost combining characters without my awareness.
I might have to revisit these later on.

For now, just copy what is there to simplify the work being done.

I used commands like the following to help generate some combining characters:

```sh
echo "first valid.$(utf8 -cB U+0301)" >> basic-combining_read.txt

echo -e "  not a valid list{$(utf8 -cB U+0301)\n}" >> extended_list-combining_read.txt
```

38 files changed:
level_1/fl_fss/data/tests/contents/basic_list-combining_read-0.txt [new file with mode: 0644]
level_1/fl_fss/data/tests/contents/basic_list-combining_read-1.txt [new file with mode: 0644]
level_1/fl_fss/data/tests/contents/basic_list-combining_read-2.txt [new file with mode: 0644]
level_1/fl_fss/data/tests/contents/basic_list-combining_read-3.txt [new file with mode: 0644]
level_1/fl_fss/data/tests/contents/basic_list-combining_read-4.txt [new file with mode: 0644]
level_1/fl_fss/data/tests/contents/basic_list-combining_read-5.txt [new file with mode: 0644]
level_1/fl_fss/data/tests/contents/embedded_list-combining_read-0.txt [new file with mode: 0644]
level_1/fl_fss/data/tests/contents/embedded_list-combining_read-1.txt [new file with mode: 0644]
level_1/fl_fss/data/tests/contents/embedded_list-combining_read-2.txt [new file with mode: 0644]
level_1/fl_fss/data/tests/contents/embedded_list-combining_read-3.txt [new file with mode: 0644]
level_1/fl_fss/data/tests/contents/embedded_list-combining_read-4.txt [new file with mode: 0644]
level_1/fl_fss/data/tests/contents/embedded_list-combining_read-5.txt [new file with mode: 0644]
level_1/fl_fss/data/tests/contents/extended_list-combining_read-0.txt [new file with mode: 0644]
level_1/fl_fss/data/tests/contents/extended_list-combining_read-1.txt [new file with mode: 0644]
level_1/fl_fss/data/tests/contents/extended_list-combining_read-2.txt [new file with mode: 0644]
level_1/fl_fss/data/tests/contents/extended_list-combining_read-3.txt [new file with mode: 0644]
level_1/fl_fss/data/tests/contents/extended_list-combining_read-4.txt [new file with mode: 0644]
level_1/fl_fss/data/tests/contents/extended_list-combining_read-5.txt [new file with mode: 0644]
level_1/fl_fss/data/tests/matches/extended_list-combining_read.txt [new file with mode: 0644]
level_1/fl_fss/data/tests/objects/basic_list-combining_read.txt [new file with mode: 0644]
level_1/fl_fss/data/tests/objects/embedded_list-combining_read.txt [new file with mode: 0644]
level_1/fl_fss/data/tests/objects/extended_list-combining_read.txt [new file with mode: 0644]
level_1/fl_fss/data/tests/strings/basic_list-combining_read.txt [new file with mode: 0644]
level_1/fl_fss/data/tests/strings/embedded_list-combining_read.txt [new file with mode: 0644]
level_1/fl_fss/data/tests/strings/extended_list-combining_read.txt [new file with mode: 0644]
level_1/fl_fss/tests/unit/c/test-fss-basic_list_content_read.c
level_1/fl_fss/tests/unit/c/test-fss-basic_list_content_read.h
level_1/fl_fss/tests/unit/c/test-fss-basic_list_object_read.c
level_1/fl_fss/tests/unit/c/test-fss-basic_list_object_read.h
level_1/fl_fss/tests/unit/c/test-fss-embedded_list_content_read.c
level_1/fl_fss/tests/unit/c/test-fss-embedded_list_content_read.h
level_1/fl_fss/tests/unit/c/test-fss-embedded_list_object_read.c
level_1/fl_fss/tests/unit/c/test-fss-embedded_list_object_read.h
level_1/fl_fss/tests/unit/c/test-fss-extended_list_content_read.c
level_1/fl_fss/tests/unit/c/test-fss-extended_list_content_read.h
level_1/fl_fss/tests/unit/c/test-fss-extended_list_object_read.c
level_1/fl_fss/tests/unit/c/test-fss-extended_list_object_read.h
level_1/fl_fss/tests/unit/c/test-fss.c

diff --git a/level_1/fl_fss/data/tests/contents/basic_list-combining_read-0.txt b/level_1/fl_fss/data/tests/contents/basic_list-combining_read-0.txt
new file mode 100644 (file)
index 0000000..b93e370
--- /dev/null
@@ -0,0 +1 @@
+  content 1.
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
new file mode 100644 (file)
index 0000000..311e0a5
--- /dev/null
@@ -0,0 +1 @@
+  is_second and content 2.
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
new file mode 100644 (file)
index 0000000..652a208
--- /dev/null
@@ -0,0 +1 @@
+  has ́ content 3.
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
new file mode 100644 (file)
index 0000000..96487d5
--- /dev/null
@@ -0,0 +1 @@
+  has ͜no_space content 4.
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
new file mode 100644 (file)
index 0000000..78c6119
--- /dev/null
@@ -0,0 +1 @@
+  content 5.
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
new file mode 100644 (file)
index 0000000..5e7418a
--- /dev/null
@@ -0,0 +1,2 @@
+  sixtẖ̚ is content 6.
+  not a valid list:́
diff --git a/level_1/fl_fss/data/tests/contents/embedded_list-combining_read-0.txt b/level_1/fl_fss/data/tests/contents/embedded_list-combining_read-0.txt
new file mode 100644 (file)
index 0000000..b93e370
--- /dev/null
@@ -0,0 +1 @@
+  content 1.
diff --git a/level_1/fl_fss/data/tests/contents/embedded_list-combining_read-1.txt b/level_1/fl_fss/data/tests/contents/embedded_list-combining_read-1.txt
new file mode 100644 (file)
index 0000000..311e0a5
--- /dev/null
@@ -0,0 +1 @@
+  is_second and content 2.
diff --git a/level_1/fl_fss/data/tests/contents/embedded_list-combining_read-2.txt b/level_1/fl_fss/data/tests/contents/embedded_list-combining_read-2.txt
new file mode 100644 (file)
index 0000000..652a208
--- /dev/null
@@ -0,0 +1 @@
+  has ́ content 3.
diff --git a/level_1/fl_fss/data/tests/contents/embedded_list-combining_read-3.txt b/level_1/fl_fss/data/tests/contents/embedded_list-combining_read-3.txt
new file mode 100644 (file)
index 0000000..96487d5
--- /dev/null
@@ -0,0 +1 @@
+  has ͜no_space content 4.
diff --git a/level_1/fl_fss/data/tests/contents/embedded_list-combining_read-4.txt b/level_1/fl_fss/data/tests/contents/embedded_list-combining_read-4.txt
new file mode 100644 (file)
index 0000000..78c6119
--- /dev/null
@@ -0,0 +1 @@
+  content 5.
diff --git a/level_1/fl_fss/data/tests/contents/embedded_list-combining_read-5.txt b/level_1/fl_fss/data/tests/contents/embedded_list-combining_read-5.txt
new file mode 100644 (file)
index 0000000..d765694
--- /dev/null
@@ -0,0 +1 @@
+  sixtẖ̚ is content 6.
diff --git a/level_1/fl_fss/data/tests/contents/extended_list-combining_read-0.txt b/level_1/fl_fss/data/tests/contents/extended_list-combining_read-0.txt
new file mode 100644 (file)
index 0000000..b93e370
--- /dev/null
@@ -0,0 +1 @@
+  content 1.
diff --git a/level_1/fl_fss/data/tests/contents/extended_list-combining_read-1.txt b/level_1/fl_fss/data/tests/contents/extended_list-combining_read-1.txt
new file mode 100644 (file)
index 0000000..311e0a5
--- /dev/null
@@ -0,0 +1 @@
+  is_second and content 2.
diff --git a/level_1/fl_fss/data/tests/contents/extended_list-combining_read-2.txt b/level_1/fl_fss/data/tests/contents/extended_list-combining_read-2.txt
new file mode 100644 (file)
index 0000000..652a208
--- /dev/null
@@ -0,0 +1 @@
+  has ́ content 3.
diff --git a/level_1/fl_fss/data/tests/contents/extended_list-combining_read-3.txt b/level_1/fl_fss/data/tests/contents/extended_list-combining_read-3.txt
new file mode 100644 (file)
index 0000000..96487d5
--- /dev/null
@@ -0,0 +1 @@
+  has ͜no_space content 4.
diff --git a/level_1/fl_fss/data/tests/contents/extended_list-combining_read-4.txt b/level_1/fl_fss/data/tests/contents/extended_list-combining_read-4.txt
new file mode 100644 (file)
index 0000000..78c6119
--- /dev/null
@@ -0,0 +1 @@
+  content 5.
diff --git a/level_1/fl_fss/data/tests/contents/extended_list-combining_read-5.txt b/level_1/fl_fss/data/tests/contents/extended_list-combining_read-5.txt
new file mode 100644 (file)
index 0000000..d765694
--- /dev/null
@@ -0,0 +1 @@
+  sixtẖ̚ is content 6.
diff --git a/level_1/fl_fss/data/tests/matches/extended_list-combining_read.txt b/level_1/fl_fss/data/tests/matches/extended_list-combining_read.txt
new file mode 100644 (file)
index 0000000..87000e7
--- /dev/null
@@ -0,0 +1,6 @@
+2
+2
+1
+1
+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
new file mode 100644 (file)
index 0000000..d2132bf
--- /dev/null
@@ -0,0 +1,6 @@
+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/objects/embedded_list-combining_read.txt b/level_1/fl_fss/data/tests/objects/embedded_list-combining_read.txt
new file mode 100644 (file)
index 0000000..d2132bf
--- /dev/null
@@ -0,0 +1,6 @@
+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/objects/extended_list-combining_read.txt b/level_1/fl_fss/data/tests/objects/extended_list-combining_read.txt
new file mode 100644 (file)
index 0000000..d2132bf
--- /dev/null
@@ -0,0 +1,6 @@
+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
new file mode 100644 (file)
index 0000000..6f47d5c
--- /dev/null
@@ -0,0 +1,13 @@
+first valid.:
+  content 1.
+is_second and does not have embedded new line.:
+  is_second and content 2.
+ ́:
+  has ́ content 3.
+fourth ͜no_space:
+  has ͜no_space content 4.
+fifth is valid.:
+  content 5.
+sixtẖ̚ is valid with two combiners.:
+  sixtẖ̚ is content 6.
+  not a valid list:́
diff --git a/level_1/fl_fss/data/tests/strings/embedded_list-combining_read.txt b/level_1/fl_fss/data/tests/strings/embedded_list-combining_read.txt
new file mode 100644 (file)
index 0000000..433b569
--- /dev/null
@@ -0,0 +1,20 @@
+first valid.{
+  content 1.
+}
+is_second and does not have embedded new line.{
+  is_second and content 2.
+}
+ ́{
+  has ́ content 3.
+}
+fourth ͜no_space{
+  has ͜no_space content 4.
+}
+fifth is valid.{
+  content 5.
+}
+sixtẖ̚ is valid with two combiners.{
+  sixtẖ̚ is content 6.
+}
+  not a valid list{́
+}
diff --git a/level_1/fl_fss/data/tests/strings/extended_list-combining_read.txt b/level_1/fl_fss/data/tests/strings/extended_list-combining_read.txt
new file mode 100644 (file)
index 0000000..433b569
--- /dev/null
@@ -0,0 +1,20 @@
+first valid.{
+  content 1.
+}
+is_second and does not have embedded new line.{
+  is_second and content 2.
+}
+ ́{
+  has ́ content 3.
+}
+fourth ͜no_space{
+  has ͜no_space content 4.
+}
+fifth is valid.{
+  content 5.
+}
+sixtẖ̚ is valid with two combiners.{
+  sixtẖ̚ is content 6.
+}
+  not a valid list{́
+}
index 5fc5f4dfe259a8fa1900dcc263975239c1d94d98..d6cfe025c55ad4c4900eca0c567485210fc7cc15 100644 (file)
@@ -330,6 +330,200 @@ void test__fl_fss_basic_list_content_read__works(void **void_state) {
   }
 }
 
+void test__fl_fss_basic_list_content_read__works_using_combining(void **void_state) {
+
+  {
+    // Note: These files are required to have the same number of lines and each line should probably be at max 255 characters.
+    FILE *file_strings = data__file_open__named("strings", "basic_list", "combining_read");
+
+    FILE *file_contents[] = {
+      data__file_open__named_at("contents", "basic_list", "combining_read", 0),
+      data__file_open__named_at("contents", "basic_list", "combining_read", 1),
+      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_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]);
+
+    size_t max = 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;
+
+    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 comments = f_ranges_t_initialize;
+    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 (;;) {
+
+      max = 255;
+
+      result = getline(&line_string, &max, file_strings);
+      if (result == -1) break;
+
+      buffer_string.string = line_string;
+      buffer_string.used = (f_number_unsigned_t) result;
+      buffer_string.size = buffer_string.used;
+
+      for (uint8_t i = 0; i < total_content; ++i) {
+
+        max = 255;
+
+        result = getline(&line_content[i], &max, file_contents[i]);
+
+        // 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;
+        }
+      } // or
+
+      state.status = F_none;
+      range.start = 0;
+      range.stop = buffer_string.used - 1;
+      found_object.start = 1;
+      found_object.stop = 0;
+
+      fl_fss_basic_list_object_read(buffer_string, &range, &found_object, &delimits, &state);
+
+      assert_true(state.status == F_fss_found_object || state.status == F_fss_found_object_not);
+
+      status_object = state.status;
+      state.status = F_none;
+
+      if (status_object == F_fss_found_object) {
+        fl_fss_basic_list_content_read(buffer_string, &range, &found, &delimits, &comments, &state);
+
+        assert_true(state.status == F_fss_found_content || state.status == F_data_not);
+
+        if (state.status == F_fss_found_content) {
+          assert_true(found.used);
+          assert_true(found.used <= (f_number_unsigned_t) total_content);
+
+          {
+            const f_status_t status = f_string_dynamic_append(buffer_string, &delimit_string);
+            assert_int_equal(status, F_okay);
+          }
+
+          state.status = F_none;
+
+          f_fss_apply_delimit(delimits, &delimit_string, &state);
+          assert_int_equal(state.status, F_okay);
+
+          {
+            uint8_t i = 0;
+
+            for (; i < found.used; ++i) {
+
+              result_string.used = 0;
+
+              {
+                const f_status_t status = f_string_dynamic_partial_append_nulless(delimit_string, found.array[i], &result_string);
+                assert_true(status == F_okay || status == F_data_not_eos);
+              }
+
+              {
+                const f_status_t status = f_string_dynamic_terminate_after(&result_string);
+                assert_int_equal(status, F_okay);
+              }
+
+              assert_string_equal(result_string.string, line_content[i]);
+            } // for
+
+            // 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);
+            }
+          }
+        }
+        else {
+          assert_true(!found.used);
+        }
+      }
+
+      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 (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
+
+      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;
+      quotes.array = 0;
+      quotes.used = 0;
+      quotes.size = 0;
+    } // for
+
+    for (uint8_t i = 0; i < total_content; ++i) {
+
+      if (file_contents[i]) fclose(file_contents[i]);
+      if (line_content[i]) free(line_content[i]);
+
+      line_content[i] = 0;
+    } // for
+
+    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 (quotes.array) free(quotes.array);
+    if (line_string) free(line_string);
+    if (result_string.string) free(result_string.string);
+    if (delimit_string.string) free(delimit_string.string);
+  }
+}
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index a80cea19e29e88e47e42f85bd388cc582d2e9277..c03c5ccd172deb7fa9b9c91765b916785a8b1d2e 100644 (file)
@@ -31,4 +31,11 @@ extern void test__fl_fss_basic_list_content_read__returns_data_not(void **state)
  */
 extern void test__fl_fss_basic_list_content_read__works(void **state);
 
+/**
+ * Test that the function works when using combining characters.
+ *
+ * @see fl_fss_basic_list_content_read()
+ */
+extern void test__fl_fss_basic_list_content_read__works_using_combining(void **state);
+
 #endif // _TEST__FL_fss_basic_list_content_read_list_h
index 683057135d65f45c828aa8e8bcc98336075f97cf..2532727181bf6fb55937af2eec8506d3b377d1e3 100644 (file)
@@ -232,6 +232,154 @@ void test__fl_fss_basic_list_object_read__works(void **void_state) {
   }
 }
 
+void test__fl_fss_basic_list_object_read__works_using_combining(void **void_state) {
+
+  {
+    FILE *file_strings = data__file_open__named("strings", "basic_list", "combining_read");
+    FILE *file_objects = data__file_open__named("objects", "basic_list", "combining_read");
+
+    assert_non_null(file_strings);
+    assert_non_null(file_objects);
+
+    size_t max = 0;
+    char *line_string = 0;
+    char *line_object = 0;
+    ssize_t result = 0;
+
+    f_string_static_t buffer_string = f_string_static_t_initialize;
+
+    f_state_t state = f_state_t_initialize;
+    f_range_t range = f_range_t_initialize;
+    f_range_t found = f_range_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;
+
+    for (int line = 1;; ++line) {
+
+      max = 255;
+
+      result = getline(&line_string, &max, file_strings);
+      if (result == -1) break;
+
+      buffer_string.string = line_string;
+      buffer_string.used = (f_number_unsigned_t) result;
+      buffer_string.size = buffer_string.used;
+
+      state.status = F_none;
+      range.start = 0;
+      range.stop = buffer_string.used - 1;
+      found.start = 1;
+      found.stop = 0;
+
+      fl_fss_basic_list_object_read(buffer_string, &range, &found, &delimits, &state);
+
+      if (!(state.status == F_fss_found_object || state.status == F_fss_found_object_not)) {
+        printf("[ -------> ] --- [00] Failure with line (%u) '%s', status=%u, expected %u or %u.\n", line, line_string, state.status, F_fss_found_object, F_fss_found_object_not);
+      }
+
+      assert_true(state.status == F_fss_found_object || state.status == F_fss_found_object_not);
+
+      if (state.status == F_fss_found_object) {
+        max = 255;
+
+        result = getline(&line_object, &max, file_objects);
+
+        if (!result) {
+          printf("[ -------> ] --- [01] Failure with line (%u) '%s', line_object = '%s', result=%zu.\n", line, line_string, line_object, result);
+        }
+
+        assert_return_code(result, 0);
+
+        // The newline is copied by getline(), and so remove that newline before comparing.
+        line_object[result - 1] = 0;
+
+        if (found.start <= found.stop) {
+          {
+            const f_status_t status = f_string_dynamic_append(buffer_string, &delimit_string);
+
+            if (status != F_okay) {
+              printf("[ -------> ] --- [02] Failure with line (%u) '%s', line_object = '%s', status=%u, expected %u.\n", line, line_string, line_object, status, F_okay);
+            }
+
+            assert_int_equal(status, F_okay);
+          }
+
+          state.status = F_none;
+
+          f_fss_apply_delimit(delimits, &delimit_string, &state);
+
+          if (state.status != F_okay) {
+            printf("[ -------> ] --- [03] Failure with line (%u) '%s', line_object = '%s', status=%u, expected %u.\n", line, line_string, line_object, state.status, F_okay);
+          }
+
+          assert_int_equal(state.status, F_okay);
+
+          {
+            const f_status_t status = f_string_dynamic_partial_append_nulless(delimit_string, found, &result_string);
+
+            if (!(status == F_okay || status == F_data_not_eos)) {
+              printf("[ -------> ] --- [04] Failure with line (%u) '%s', line_object = '%s', status=%u, expected %u or %u.\n", line, line_string, line_object, status, F_okay, F_data_not_eos);
+            }
+
+            assert_true(status == F_okay || status == F_data_not_eos);
+          }
+
+          {
+            const f_status_t status = f_string_dynamic_terminate_after(&result_string);
+
+            if (status != F_okay) {
+              printf("[ -------> ] --- [05] Failure with line (%u) '%s', line_object = '%s', status=%u, expected %u.\n", line, line_string, line_object, status, F_okay);
+            }
+
+            assert_int_equal(status, F_okay);
+          }
+
+          if (strncmp(result_string.string, line_object, result_string.used)) {
+            printf("[ -------> ] --- [06] Failure with line (%u) '%s', line_object = '%s', result '%s'.\n", line, line_string, line_object, result_string.string);
+          }
+
+          assert_string_equal(result_string.string, line_object);
+        }
+        else {
+          if (line_object[0]) {
+            printf("[ -------> ] --- [07] Failure with line (%u) '%s', line_object[0]=%c.\n", line, line_string, line_object[0]);
+          }
+
+          assert_int_equal(line_object[0], 0);
+        }
+      }
+
+      if (line_string) free(line_string);
+      if (line_object) free(line_object);
+      if (result_string.string) free(result_string.string);
+      if (delimit_string.string) free(delimit_string.string);
+      if (delimits.array) free(delimits.array);
+
+      line_string = 0;
+      line_object = 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;
+    } // for
+
+    if (file_strings) fclose(file_strings);
+    if (file_objects) fclose(file_objects);
+
+    if (delimits.array) free(delimits.array);
+    if (line_string) free(line_string);
+    if (line_object) free(line_object);
+    if (result_string.string) free(result_string.string);
+    if (delimit_string.string) free(delimit_string.string);
+  }
+}
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index 286895daa3a07cd1af7814c02436640e231e1625..84b13d538fe04a6b1bf82e78e5e3851cb13be5d5 100644 (file)
@@ -31,4 +31,11 @@ extern void test__fl_fss_basic_list_object_read__returns_data_not(void **state);
  */
 extern void test__fl_fss_basic_list_object_read__works(void **state);
 
+/**
+ * Test that the function works when using combining characters.
+ *
+ * @see fl_fss_basic_list_object_read()
+ */
+extern void test__fl_fss_basic_list_object_read__works_using_combining(void **state);
+
 #endif // _TEST__FL_fss_basic_list_object_read_list_h
index 57c5030f69ba92648184bce877a7e2358fc6d1ae..906783f84906f6c64e354b0110cf227c064b02be 100644 (file)
@@ -344,6 +344,176 @@ void test__fl_fss_embedded_list_content_read__works(void **void_state) {
   }
 }
 
+void test__fl_fss_embedded_list_content_read__works_using_combining(void **void_state) {
+
+  {
+    // Note: These files are required to have the same number of lines and each line should probably be at max 255 characters.
+    FILE *file_strings = data__file_open__named("strings", "embedded_list", "combining_read");
+
+    FILE *file_contents[] = {
+      data__file_open__named_at("contents", "embedded_list", "combining_read", 0),
+      data__file_open__named_at("contents", "embedded_list", "combining_read", 1),
+      data__file_open__named_at("contents", "embedded_list", "combining_read", 2),
+      data__file_open__named_at("contents", "embedded_list", "combining_read", 3),
+      data__file_open__named_at("contents", "embedded_list", "combining_read", 4),
+      data__file_open__named_at("contents", "embedded_list", "combining_read", 5),
+    };
+
+    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]);
+
+    size_t max = 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;
+
+    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_fss_nest_t found = f_fss_nest_t_initialize;
+    f_ranges_t comments = f_ranges_t_initialize;
+    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;
+
+    f_ranges_t objects = f_ranges_t_initialize;
+    f_number_unsigneds_t positions = f_number_unsigneds_t_initialize;
+    f_number_unsigneds_t slashes = f_number_unsigneds_t_initialize;
+    fl_fss_data_embedded_list_t cache = macro_fl_fss_data_embedded_list_t_initialize_1(&objects, &positions, &slashes);
+
+    state.data = (void *) &cache;
+
+    for (;;) {
+
+      max = 255;
+
+      result = getline(&line_string, &max, file_strings);
+      if (result == -1) break;
+
+      buffer_string.string = line_string;
+      buffer_string.used = (f_number_unsigned_t) result;
+      buffer_string.size = buffer_string.used;
+
+      for (uint8_t i = 0; i < total_content; ++i) {
+
+        max = 255;
+
+        result = getline(&line_content[i], &max, file_contents[i]);
+
+        // 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;
+        }
+      } // or
+
+      state.status = F_none;
+      range.start = 0;
+      range.stop = buffer_string.used - 1;
+      found_object.start = 1;
+      found_object.stop = 0;
+
+      fl_fss_embedded_list_object_read(buffer_string, &range, &found_object, &delimits, &state);
+
+      assert_true(state.status == F_fss_found_object || state.status == F_fss_found_object_not);
+
+      status_object = state.status;
+      state.status = F_none;
+
+      if (status_object == F_fss_found_object) {
+        fl_fss_embedded_list_content_read(buffer_string, &range, &found, &delimits, &comments, &state);
+
+        assert_true(state.status == F_fss_found_content || state.status == F_data_not);
+
+        if (state.status == F_fss_found_content) {
+          // @todo
+        }
+        else {
+          assert_true(!found.used);
+        }
+      }
+
+      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 (comments.array) free(comments.array);
+      if (quotes.array) free(quotes.array);
+
+      f_fss_nest_delete(&found);
+
+      for (uint8_t i = 0; i < total_content; ++i) {
+
+        if (line_content[i]) free(line_content[i]);
+
+        line_content[i] = 0;
+      } // for
+
+      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.depth = 0;
+      found.used = 0;
+      found.size = 0;
+      comments.array = 0;
+      comments.used = 0;
+      comments.size = 0;
+      quotes.array = 0;
+      quotes.used = 0;
+      quotes.size = 0;
+    } // for
+
+    for (uint8_t i = 0; i < total_content; ++i) {
+
+      if (file_contents[i]) fclose(file_contents[i]);
+      if (line_content[i]) free(line_content[i]);
+
+      line_content[i] = 0;
+    } // for
+
+    if (file_strings) fclose(file_strings);
+
+    if (delimits.array) free(delimits.array);
+    if (comments.array) free(comments.array);
+    if (quotes.array) free(quotes.array);
+    if (line_string) free(line_string);
+    if (result_string.string) free(result_string.string);
+    if (delimit_string.string) free(delimit_string.string);
+
+    if (objects.array) free(objects.array);
+    if (positions.array) free(positions.array);
+    if (slashes.array) free(slashes.array);
+
+    f_fss_nest_delete(&found);
+  }
+}
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index 9b35e5343ee3ae8f23c816ec8e215fc11e3d6250..37149041877f845ad30ce747560a253157c28a57 100644 (file)
@@ -31,4 +31,11 @@ extern void test__fl_fss_embedded_list_content_read__returns_data_not(void **sta
  */
 extern void test__fl_fss_embedded_list_content_read__works(void **state);
 
+/**
+ * Test that the function works when using combining characters.
+ *
+ * @see fl_fss_embedded_list_content_read()
+ */
+extern void test__fl_fss_embedded_list_content_read__works_using_combining(void **state);
+
 #endif // _TEST__FL_fss_embedded_list_content_read_h
index a253df8b5bda6726b433e5d549c09d6f0858a067..d0f4d4bc84c1bf9638df689da2bd09de6bfd908c 100644 (file)
@@ -232,6 +232,154 @@ void test__fl_fss_embedded_list_object_read__works(void **void_state) {
   }
 }
 
+void test__fl_fss_embedded_list_object_read__works_using_combining(void **void_state) {
+
+  {
+    FILE *file_strings = data__file_open__named("strings", "embedded_list", "combining_read");
+    FILE *file_objects = data__file_open__named("objects", "embedded_list", "combining_read");
+
+    assert_non_null(file_strings);
+    assert_non_null(file_objects);
+
+    size_t max = 0;
+    char *line_string = 0;
+    char *line_object = 0;
+    ssize_t result = 0;
+
+    f_string_static_t buffer_string = f_string_static_t_initialize;
+
+    f_state_t state = f_state_t_initialize;
+    f_range_t range = f_range_t_initialize;
+    f_range_t found = f_range_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;
+
+    for (int line = 1;; ++line) {
+
+      max = 255;
+
+      result = getline(&line_string, &max, file_strings);
+      if (result == -1) break;
+
+      buffer_string.string = line_string;
+      buffer_string.used = (f_number_unsigned_t) result;
+      buffer_string.size = buffer_string.used;
+
+      state.status = F_none;
+      range.start = 0;
+      range.stop = buffer_string.used - 1;
+      found.start = 1;
+      found.stop = 0;
+
+      fl_fss_embedded_list_object_read(buffer_string, &range, &found, &delimits, &state);
+
+      if (!(state.status == F_fss_found_object || state.status == F_fss_found_object_not)) {
+        printf("[ -------> ] --- [00] Failure with line (%u) '%s', status=%u, expected %u or %u.\n", line, line_string, state.status, F_fss_found_object, F_fss_found_object_not);
+      }
+
+      assert_true(state.status == F_fss_found_object || state.status == F_fss_found_object_not);
+
+      if (state.status == F_fss_found_object) {
+        max = 255;
+
+        result = getline(&line_object, &max, file_objects);
+
+        if (!result) {
+          printf("[ -------> ] --- [01] Failure with line (%u) '%s', line_object = '%s', result=%zu.\n", line, line_string, line_object, result);
+        }
+
+        assert_return_code(result, 0);
+
+        // The newline is copied by getline(), and so remove that newline before comparing.
+        line_object[result - 1] = 0;
+
+        if (found.start <= found.stop) {
+          {
+            const f_status_t status = f_string_dynamic_append(buffer_string, &delimit_string);
+
+            if (status != F_okay) {
+              printf("[ -------> ] --- [02] Failure with line (%u) '%s', line_object = '%s', status=%u, expected %u.\n", line, line_string, line_object, status, F_okay);
+            }
+
+            assert_int_equal(status, F_okay);
+          }
+
+          state.status = F_none;
+
+          f_fss_apply_delimit(delimits, &delimit_string, &state);
+
+          if (state.status != F_okay) {
+            printf("[ -------> ] --- [03] Failure with line (%u) '%s', line_object = '%s', status=%u, expected %u.\n", line, line_string, line_object, state.status, F_okay);
+          }
+
+          assert_int_equal(state.status, F_okay);
+
+          {
+            const f_status_t status = f_string_dynamic_partial_append_nulless(delimit_string, found, &result_string);
+
+            if (!(status == F_okay || status == F_data_not_eos)) {
+              printf("[ -------> ] --- [04] Failure with line (%u) '%s', line_object = '%s', status=%u, expected %u or %u.\n", line, line_string, line_object, status, F_okay, F_data_not_eos);
+            }
+
+            assert_true(status == F_okay || status == F_data_not_eos);
+          }
+
+          {
+            const f_status_t status = f_string_dynamic_terminate_after(&result_string);
+
+            if (status != F_okay) {
+              printf("[ -------> ] --- [05] Failure with line (%u) '%s', line_object = '%s', status=%u, expected %u.\n", line, line_string, line_object, status, F_okay);
+            }
+
+            assert_int_equal(status, F_okay);
+          }
+
+          if (strncmp(result_string.string, line_object, result_string.used)) {
+            printf("[ -------> ] --- [06] Failure with line (%u) '%s', line_object = '%s', result '%s'.\n", line, line_string, line_object, result_string.string);
+          }
+
+          assert_string_equal(result_string.string, line_object);
+        }
+        else {
+          if (line_object[0]) {
+            printf("[ -------> ] --- [07] Failure with line (%u) '%s', line_object[0]=%c.\n", line, line_string, line_object[0]);
+          }
+
+          assert_int_equal(line_object[0], 0);
+        }
+      }
+
+      if (line_string) free(line_string);
+      if (line_object) free(line_object);
+      if (result_string.string) free(result_string.string);
+      if (delimit_string.string) free(delimit_string.string);
+      if (delimits.array) free(delimits.array);
+
+      line_string = 0;
+      line_object = 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;
+    } // for
+
+    if (file_strings) fclose(file_strings);
+    if (file_objects) fclose(file_objects);
+
+    if (delimits.array) free(delimits.array);
+    if (line_string) free(line_string);
+    if (line_object) free(line_object);
+    if (result_string.string) free(result_string.string);
+    if (delimit_string.string) free(delimit_string.string);
+  }
+}
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index 1c11751cea961a1e0d0869521c1fd3f3f17032bd..6ae5fed669f223e0d3d1ff2374ded0edf2dafea3 100644 (file)
@@ -31,4 +31,11 @@ extern void test__fl_fss_embedded_list_object_read__returns_data_not(void **stat
  */
 extern void test__fl_fss_embedded_list_object_read__works(void **state);
 
+/**
+ * Test that the function works when using combining characters.
+ *
+ * @see fl_fss_embedded_list_object_read()
+ */
+extern void test__fl_fss_embedded_list_object_read__works_using_combining(void **state);
+
 #endif // _TEST__FL_fss_embedded_list_object_read_h
index b7129e9819e7de1d65dad6b9b901acda240a168f..c2095647ef5e5ee8f6040a2ac20b390a1a3b7fe2 100644 (file)
@@ -461,6 +461,201 @@ void test__fl_fss_extended_list_content_read__works(void **void_state) {
   }
 }
 
+void test__fl_fss_extended_list_content_read__works_using_combining(void **void_state) {
+
+  {
+    // Note: These files are required to have the same number of lines and each line should probably be at max 255 characters.
+    FILE *file_strings = data__file_open__named("strings", "extended_list", "combining_read");
+
+    FILE *file_contents[] = {
+      data__file_open__named_at("contents", "extended_list", "combining_read", 0),
+      data__file_open__named_at("contents", "extended_list", "combining_read", 1),
+      data__file_open__named_at("contents", "extended_list", "combining_read", 2),
+      data__file_open__named_at("contents", "extended_list", "combining_read", 3),
+      data__file_open__named_at("contents", "extended_list", "combining_read", 4),
+      data__file_open__named_at("contents", "extended_list", "combining_read", 5),
+    };
+
+    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]);
+
+    size_t max = 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;
+
+    f_state_t state = f_state_t_initialize;
+    f_range_t close = f_range_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 comments = f_ranges_t_initialize;
+    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 (;;) {
+
+      max = 255;
+
+      result = getline(&line_string, &max, file_strings);
+      if (result == -1) break;
+
+      buffer_string.string = line_string;
+      buffer_string.used = (f_number_unsigned_t) result;
+      buffer_string.size = buffer_string.used;
+
+      for (uint8_t i = 0; i < total_content; ++i) {
+
+        max = 255;
+
+        result = getline(&line_content[i], &max, file_contents[i]);
+
+        // 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;
+        }
+      } // or
+
+      state.status = F_none;
+      range.start = 0;
+      range.stop = buffer_string.used - 1;
+      found_object.start = 1;
+      found_object.stop = 0;
+
+      fl_fss_extended_list_object_read(buffer_string, &range, &found_object, &delimits, &state);
+
+      assert_true(state.status == F_fss_found_object || state.status == F_fss_found_object_not);
+
+      status_object = state.status;
+      state.status = F_none;
+
+      if (status_object == F_fss_found_object) {
+        fl_fss_extended_list_content_read(buffer_string, &range, &found, &close, &delimits, &comments, &state);
+
+        assert_true(state.status == F_fss_found_content || state.status == F_data_not);
+
+        if (state.status == F_fss_found_content) {
+          assert_true(found.used);
+          assert_true(found.used <= (f_number_unsigned_t) total_content);
+
+          {
+            const f_status_t status = f_string_dynamic_append(buffer_string, &delimit_string);
+            assert_int_equal(status, F_okay);
+          }
+
+          state.status = F_none;
+
+          f_fss_apply_delimit(delimits, &delimit_string, &state);
+          assert_int_equal(state.status, F_okay);
+
+          {
+            uint8_t i = 0;
+
+            for (; i < found.used; ++i) {
+
+              result_string.used = 0;
+
+              {
+                const f_status_t status = f_string_dynamic_partial_append_nulless(delimit_string, found.array[i], &result_string);
+                assert_true(status == F_okay || status == F_data_not_eos);
+              }
+
+              {
+                const f_status_t status = f_string_dynamic_terminate_after(&result_string);
+                assert_int_equal(status, F_okay);
+              }
+
+              assert_string_equal(result_string.string, line_content[i]);
+            } // for
+
+            // 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);
+            }
+          }
+        }
+        else {
+          assert_true(!found.used);
+        }
+      }
+
+      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 (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
+
+      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;
+      quotes.array = 0;
+      quotes.used = 0;
+      quotes.size = 0;
+    } // for
+
+    for (uint8_t i = 0; i < total_content; ++i) {
+
+      if (file_contents[i]) fclose(file_contents[i]);
+      if (line_content[i]) free(line_content[i]);
+
+      line_content[i] = 0;
+    } // for
+
+    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 (quotes.array) free(quotes.array);
+    if (line_string) free(line_string);
+    if (result_string.string) free(result_string.string);
+    if (delimit_string.string) free(delimit_string.string);
+  }
+}
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index 869efda4c963cd0e805cda832d5bcb3e489370e5..a57216b9aeb6baaef9626a47b8e3e296c5112a03 100644 (file)
@@ -31,4 +31,11 @@ extern void test__fl_fss_extended_list_content_read__returns_data_not(void **sta
  */
 extern void test__fl_fss_extended_list_content_read__works(void **state);
 
+/**
+ * Test that the function works when using combining characters.
+ *
+ * @see fl_fss_extended_list_content_read()
+ */
+extern void test__fl_fss_extended_list_content_read__works_using_combining(void **state);
+
 #endif // _TEST__FL_fss_extended_list_content_read_list_h
index 6c94852b61e310337a48edd38fdcf9c35b131dbb..0f27bd68605be36625fa7831f17398b26e774181 100644 (file)
@@ -232,6 +232,154 @@ void test__fl_fss_extended_list_object_read__works(void **void_state) {
   }
 }
 
+void test__fl_fss_extended_list_object_read__works_using_combining(void **void_state) {
+
+  {
+    FILE *file_strings = data__file_open__named("strings", "extended_list", "combining_read");
+    FILE *file_objects = data__file_open__named("objects", "extended_list", "combining_read");
+
+    assert_non_null(file_strings);
+    assert_non_null(file_objects);
+
+    size_t max = 0;
+    char *line_string = 0;
+    char *line_object = 0;
+    ssize_t result = 0;
+
+    f_string_static_t buffer_string = f_string_static_t_initialize;
+
+    f_state_t state = f_state_t_initialize;
+    f_range_t range = f_range_t_initialize;
+    f_range_t found = f_range_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;
+
+    for (int line = 1;; ++line) {
+
+      max = 255;
+
+      result = getline(&line_string, &max, file_strings);
+      if (result == -1) break;
+
+      buffer_string.string = line_string;
+      buffer_string.used = (f_number_unsigned_t) result;
+      buffer_string.size = buffer_string.used;
+
+      state.status = F_none;
+      range.start = 0;
+      range.stop = buffer_string.used - 1;
+      found.start = 1;
+      found.stop = 0;
+
+      fl_fss_extended_list_object_read(buffer_string, &range, &found, &delimits, &state);
+
+      if (!(state.status == F_fss_found_object || state.status == F_fss_found_object_not)) {
+        printf("[ -------> ] --- [00] Failure with line (%u) '%s', status=%u, expected %u or %u.\n", line, line_string, state.status, F_fss_found_object, F_fss_found_object_not);
+      }
+
+      assert_true(state.status == F_fss_found_object || state.status == F_fss_found_object_not);
+
+      if (state.status == F_fss_found_object) {
+        max = 255;
+
+        result = getline(&line_object, &max, file_objects);
+
+        if (!result) {
+          printf("[ -------> ] --- [01] Failure with line (%u) '%s', line_object = '%s', result=%zu.\n", line, line_string, line_object, result);
+        }
+
+        assert_return_code(result, 0);
+
+        // The newline is copied by getline(), and so remove that newline before comparing.
+        line_object[result - 1] = 0;
+
+        if (found.start <= found.stop) {
+          {
+            const f_status_t status = f_string_dynamic_append(buffer_string, &delimit_string);
+
+            if (status != F_okay) {
+              printf("[ -------> ] --- [02] Failure with line (%u) '%s', line_object = '%s', status=%u, expected %u.\n", line, line_string, line_object, status, F_okay);
+            }
+
+            assert_int_equal(status, F_okay);
+          }
+
+          state.status = F_none;
+
+          f_fss_apply_delimit(delimits, &delimit_string, &state);
+
+          if (state.status != F_okay) {
+            printf("[ -------> ] --- [03] Failure with line (%u) '%s', line_object = '%s', status=%u, expected %u.\n", line, line_string, line_object, state.status, F_okay);
+          }
+
+          assert_int_equal(state.status, F_okay);
+
+          {
+            const f_status_t status = f_string_dynamic_partial_append_nulless(delimit_string, found, &result_string);
+
+            if (!(status == F_okay || status == F_data_not_eos)) {
+              printf("[ -------> ] --- [04] Failure with line (%u) '%s', line_object = '%s', status=%u, expected %u or %u.\n", line, line_string, line_object, status, F_okay, F_data_not_eos);
+            }
+
+            assert_true(status == F_okay || status == F_data_not_eos);
+          }
+
+          {
+            const f_status_t status = f_string_dynamic_terminate_after(&result_string);
+
+            if (status != F_okay) {
+              printf("[ -------> ] --- [05] Failure with line (%u) '%s', line_object = '%s', status=%u, expected %u.\n", line, line_string, line_object, status, F_okay);
+            }
+
+            assert_int_equal(status, F_okay);
+          }
+
+          if (strncmp(result_string.string, line_object, result_string.used)) {
+            printf("[ -------> ] --- [06] Failure with line (%u) '%s', line_object = '%s', result '%s'.\n", line, line_string, line_object, result_string.string);
+          }
+
+          assert_string_equal(result_string.string, line_object);
+        }
+        else {
+          if (line_object[0]) {
+            printf("[ -------> ] --- [07] Failure with line (%u) '%s', line_object[0]=%c.\n", line, line_string, line_object[0]);
+          }
+
+          assert_int_equal(line_object[0], 0);
+        }
+      }
+
+      if (line_string) free(line_string);
+      if (line_object) free(line_object);
+      if (result_string.string) free(result_string.string);
+      if (delimit_string.string) free(delimit_string.string);
+      if (delimits.array) free(delimits.array);
+
+      line_string = 0;
+      line_object = 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;
+    } // for
+
+    if (file_strings) fclose(file_strings);
+    if (file_objects) fclose(file_objects);
+
+    if (delimits.array) free(delimits.array);
+    if (line_string) free(line_string);
+    if (line_object) free(line_object);
+    if (result_string.string) free(result_string.string);
+    if (delimit_string.string) free(delimit_string.string);
+  }
+}
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index 03b72f1a5587d6f0f92a77bbd6fd92163ae81924..f44a29bfd0b4cf33ac49118d7796d3c2729a643c 100644 (file)
@@ -31,4 +31,11 @@ extern void test__fl_fss_extended_list_object_read__returns_data_not(void **stat
  */
 extern void test__fl_fss_extended_list_object_read__works(void **state);
 
+/**
+ * Test that the function works when using combining characters.
+ *
+ * @see fl_fss_extended_list_object_read()
+ */
+extern void test__fl_fss_extended_list_object_read__works_using_combining(void **state);
+
 #endif // _TEST__FL_fss_extended_list_object_read_list_h
index fffdb5c71555c39c4ce659e84cb6d51461935aee..2c9b604730b35d3656586db78cbb770ecbef2528 100644 (file)
@@ -35,7 +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_object_read__works),
+    //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),
@@ -43,7 +45,9 @@ int main(void) {
     cmocka_unit_test(test__fl_fss_embedded_list_object_write__returns_data_not),
 
     cmocka_unit_test(test__fl_fss_embedded_list_content_read__works),
+    //cmocka_unit_test(test__fl_fss_embedded_list_content_read__works_using_combining),
     cmocka_unit_test(test__fl_fss_embedded_list_object_read__works),
+    //cmocka_unit_test(test__fl_fss_embedded_list_object_read__works_using_combining),
 
     cmocka_unit_test(test__fl_fss_extended_content_read__returns_data_not),
     cmocka_unit_test(test__fl_fss_extended_content_write__returns_data_not),
@@ -61,7 +65,9 @@ int main(void) {
     cmocka_unit_test(test__fl_fss_extended_list_object_write__returns_data_not),
 
     cmocka_unit_test(test__fl_fss_extended_list_content_read__works),
+    //cmocka_unit_test(test__fl_fss_extended_list_content_read__works_using_combining),
     cmocka_unit_test(test__fl_fss_extended_list_object_read__works),
+    //cmocka_unit_test(test__fl_fss_extended_list_object_read__works_using_combining),
 
     cmocka_unit_test(test__fl_fss_payload_header_map__returns_data_not),
     cmocka_unit_test(test__fl_fss_payload_header_map__abstruse_dynamic__works_join),