]> Kevux Git Server - fll/commitdiff
Feature: Add fl_path_clean() for stripping out NULLs and redundant slashes. development
authorKevin Day <Kevin@kevux.org>
Wed, 22 Jan 2025 04:09:22 +0000 (22:09 -0600)
committerKevin Day <Kevin@kevux.org>
Wed, 22 Jan 2025 04:09:22 +0000 (22:09 -0600)
build/stand_alone/fake.config.h
build/stand_alone/firewall.config.h
level_1/fl_path/c/path.c
level_1/fl_path/c/path.h
level_1/fl_path/data/build/settings-tests
level_1/fl_path/tests/unit/c/test-path-clean.c [new file with mode: 0644]
level_1/fl_path/tests/unit/c/test-path-clean.h [new file with mode: 0644]
level_1/fl_path/tests/unit/c/test-path.c
level_1/fl_path/tests/unit/c/test-path.h

index a2cda19799acc1c280d7138f666cec61251597a7..2ba861872a52750ca41f4cf66da389e1d469c11c 100644 (file)
 #define _di_fl_iki_eki_read_
 //#define _di_fl_iki_read_
 //#define _di_fl_path_canonical_
+#define _di_fl_path_clean_
 //#define _di_fl_print_debug_s_
 //#define _di_fl_print_error_s_
 //#define _di_fl_print_format_
index 95ec51a2892468a823469f61172db449deaa4ad6..9e6d8e5876a059309221590dbd2997c9ccdeecff 100644 (file)
 #define _di_fl_iki_eki_read_
 #define _di_fl_iki_read_
 #define _di_fl_path_canonical_
+#define _di_fl_path_clean_
 //#define _di_fl_print_debug_s_
 //#define _di_fl_print_error_s_
 //#define _di_fl_print_format_
index 1c30d7415c3a08cd75522e23d7cd699c28e300b4..84630665e1f1d23d9f2d04e587cd452cd7c5467e 100644 (file)
@@ -143,6 +143,54 @@ extern "C" {
   }
 #endif // _di_fl_path_canonical_
 
+#ifndef _di_fl_path_clean_
+  f_status_t fl_path_clean(const f_string_static_t path, f_string_dynamic_t * const clean) {
+    #ifndef _di_level_1_parameter_checking_
+      if (!clean) return F_status_set_error(F_parameter);
+    #endif // _di_level_1_parameter_checking_
+
+    if (!path.used) return F_okay;
+
+    f_status_t status = F_okay;
+    f_number_unsigned_t at = 0;
+    f_number_unsigned_t position = 0;
+    f_number_unsigned_t size_chunk = 0;
+
+    while (at < path.used) {
+
+      if (path.string[at] == f_path_separator_s.string[0]) {
+        status = f_string_append_nulless(path.string + position, size_chunk + 1, clean);
+        if (F_status_is_error(status)) return status;
+
+        position = at;
+
+        while (at < path.used && (!path.string[at] || path.string[at] == f_path_separator_s.string[0])) ++at;
+
+        position = at;
+        size_chunk = 0;
+
+        if (at == path.used) break;
+      }
+      else {
+        ++size_chunk;
+        ++at;
+      }
+    } // while
+
+    if (size_chunk) {
+      status = f_string_append_nulless(path.string + position, size_chunk, clean);
+      if (F_status_is_error(status)) return status;
+    }
+
+    // Assure there is no trailing forward slash, unless it is the first slash.
+    if (clean->used > 1 && clean->string[clean->used - 1] == f_path_separator_s.string[0]) {
+      --clean->used;
+    }
+
+    return F_okay;
+  }
+#endif // _di_fl_path_clean_
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index 6fa567e6e4c1dc53aaf6e533401a1b4212b116fb..d5ae40b8fa1f6ee312090b1f9e8e44cb26075b79 100644 (file)
@@ -59,6 +59,39 @@ extern "C" {
   extern f_status_t fl_path_canonical(const f_string_static_t path, f_string_dynamic_t * const canonical);
 #endif // _di_fl_path_canonical_
 
+/**
+ * Get the cleaned up path for some path, removing redundant slashes.
+ *
+ * This does not check if the path exists or not.
+ * This leaves relative parts in place: './', '../', and extra '/'.
+ * This does not process symbolic links.
+ * This has a max size of F_string_t_size_d.
+ * This removes trailing slashes, but leaves the leading slash ('/' remains as-is, but '/a/' becomes '/a').
+ * This removes redundant slashes '/'.
+ *
+ * An empty path (first character is NULL or path.used is 0) appends only the current path to canonical.
+ *
+ * @param path
+ *   The source path to determine what the canonical path is.
+ *   NULLs within the path are not copied to the clean.
+ *   This need not be NULL terminated.
+ * @param simple
+ *   The (allocated) cleaned up file path.
+ *   This will be NULL terminated at clean->used + 1.
+ *
+ * @return
+ *   F_okay on success.
+ *
+ *   Errors (with error bit) from: f_string_append_nulless().
+ *   Errors (with error bit) from: f_string_dynamic_append_assure().
+ *
+ * @see f_string_append_nulless()
+ * @see f_string_dynamic_append_assure()
+ */
+#ifndef _di_fl_path_clean_
+  extern f_status_t fl_path_clean(const f_string_static_t path, f_string_dynamic_t * const clean);
+#endif // _di_fl_path_clean_
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index d8bee0616c89820c8a6d6c05b5c8def91b05cd6e..d6172048721a6041235a83b4c8d85d5594afb784 100644 (file)
@@ -25,7 +25,7 @@ build_language c
 build_libraries -lc -lcmocka
 build_libraries-individual -lf_memory -lf_path -lf_string -lfl_path
 
-build_sources_program test-path-canonical.c
+build_sources_program test-path-canonical.c test-path-clean.c
 
 build_sources_program test-path.c
 
diff --git a/level_1/fl_path/tests/unit/c/test-path-clean.c b/level_1/fl_path/tests/unit/c/test-path-clean.c
new file mode 100644 (file)
index 0000000..827baea
--- /dev/null
@@ -0,0 +1,352 @@
+#include "test-path.h"
+#include "test-path-clean.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__fl_path_clean__back_paths(void **state) {
+
+  const f_string_static_t contents[] = {
+    macro_f_string_static_t_initialize_1("a/../", 0, 5),
+    macro_f_string_static_t_initialize_1("a/../b", 0, 6),
+    macro_f_string_static_t_initialize_1("a/../b/", 0, 7),
+    macro_f_string_static_t_initialize_1("a/../b/c", 0, 8),
+    macro_f_string_static_t_initialize_1("a/../b/c/", 0, 9),
+    macro_f_string_static_t_initialize_1("a/../b/c//", 0, 10),
+    macro_f_string_static_t_initialize_1("a/.././", 0, 7),
+    macro_f_string_static_t_initialize_1("a/.././b", 0, 8),
+    macro_f_string_static_t_initialize_1("a/.././b/", 0, 9),
+    macro_f_string_static_t_initialize_1("a/.././b/c", 0, 10),
+    macro_f_string_static_t_initialize_1("a/.././b/c/", 0, 11),
+    macro_f_string_static_t_initialize_1("a/.././b/c//", 0, 12),
+    macro_f_string_static_t_initialize_1("a/.././/", 0, 8),
+    macro_f_string_static_t_initialize_1("a/.././/b", 0, 9),
+    macro_f_string_static_t_initialize_1("a/.././/b/", 0, 10),
+    macro_f_string_static_t_initialize_1("a/.././/b/c", 0, 11),
+    macro_f_string_static_t_initialize_1("a/.././/b/c/", 0, 12),
+    macro_f_string_static_t_initialize_1("a/.././/b/c//", 0, 13),
+    macro_f_string_static_t_initialize_1("/z/../", 0, 6),
+    macro_f_string_static_t_initialize_1("/z/../b", 0, 7),
+    macro_f_string_static_t_initialize_1("/z/../b/", 0, 8),
+    macro_f_string_static_t_initialize_1("/z/../b/c", 0, 9),
+    macro_f_string_static_t_initialize_1("/z/../b/c/", 0, 10),
+    macro_f_string_static_t_initialize_1("/z/../b/c//", 0, 11),
+    macro_f_string_static_t_initialize_1("/z/.\0./b/c//", 0, 12),
+    macro_f_string_static_t_initialize_1("/z\0/.\0./b/c/\0/", 0, 14),
+    macro_f_string_static_t_initialize_1("\0a/../", 0, 6),
+    macro_f_string_static_t_initialize_1("a/../\0", 0, 6),
+  };
+
+  const f_string_static_t expected[] = {
+    macro_f_string_static_t_initialize_1("a/..", 0, 4),
+    macro_f_string_static_t_initialize_1("a/../b", 0, 6),
+    macro_f_string_static_t_initialize_1("a/../b", 0, 6),
+    macro_f_string_static_t_initialize_1("a/../b/c", 0, 8),
+    macro_f_string_static_t_initialize_1("a/../b/c", 0, 8),
+    macro_f_string_static_t_initialize_1("a/../b/c", 0, 8),
+    macro_f_string_static_t_initialize_1("a/../.", 0, 6),
+    macro_f_string_static_t_initialize_1("a/.././b", 0, 8),
+    macro_f_string_static_t_initialize_1("a/.././b", 0, 8),
+    macro_f_string_static_t_initialize_1("a/.././b/c", 0, 10),
+    macro_f_string_static_t_initialize_1("a/.././b/c", 0, 10),
+    macro_f_string_static_t_initialize_1("a/.././b/c", 0, 10),
+    macro_f_string_static_t_initialize_1("a/../.", 0, 6),
+    macro_f_string_static_t_initialize_1("a/.././b", 0, 8),
+    macro_f_string_static_t_initialize_1("a/.././b", 0, 8),
+    macro_f_string_static_t_initialize_1("a/.././b/c", 0, 10),
+    macro_f_string_static_t_initialize_1("a/.././b/c", 0, 10),
+    macro_f_string_static_t_initialize_1("a/.././b/c", 0, 10),
+    macro_f_string_static_t_initialize_1("/z/..", 0, 5),
+    macro_f_string_static_t_initialize_1("/z/../b", 0, 7),
+    macro_f_string_static_t_initialize_1("/z/../b", 0, 7),
+    macro_f_string_static_t_initialize_1("/z/../b/c", 0, 9),
+    macro_f_string_static_t_initialize_1("/z/../b/c", 0, 9),
+    macro_f_string_static_t_initialize_1("/z/../b/c", 0, 9),
+    macro_f_string_static_t_initialize_1("/z/../b/c", 0, 9),
+    macro_f_string_static_t_initialize_1("/z/../b/c", 0, 9),
+    macro_f_string_static_t_initialize_1("a/..", 0, 4),
+    macro_f_string_static_t_initialize_1("a/..", 0, 4),
+  };
+
+  f_string_dynamic_t path = f_string_dynamic_t_initialize;
+
+  for (uint8_t i = 0; i < 28; ++i) {
+
+    path.used = 0;
+
+    const f_status_t status = fl_path_clean(contents[i], &path);
+
+    assert_int_equal(status, F_okay);
+
+    // Assert_string_equal() is NULL terminated, so ensure NULL termination at end of path.used.
+    path.string[path.used] = 0;
+
+    assert_int_equal(expected[i].used, path.used);
+    assert_string_equal(expected[i].string, path.string);
+
+    memset(path.string, 0, path.used);
+  } // for
+
+  free((void *) path.string);
+}
+
+void test__fl_path_clean__empty_stays_empty(void **state) {
+
+  f_string_dynamic_t path = f_string_dynamic_t_initialize;
+
+  {
+    const f_status_t status = fl_path_clean(f_string_empty_s, &path);
+
+    assert_int_equal(status, F_okay);
+    assert_int_equal(path.used, path.used);
+  } // for
+
+  free((void *) path.string);
+}
+
+void test__fl_path_clean__present_paths(void **state) {
+
+  const f_string_static_t contents[] = {
+    macro_f_string_static_t_initialize_1("", 0, 1),
+    macro_f_string_static_t_initialize_1("a", 0, 2),
+    macro_f_string_static_t_initialize_1("a/", 0, 3),
+    macro_f_string_static_t_initialize_1("a/b", 0, 4),
+    macro_f_string_static_t_initialize_1("a/b/", 0, 5),
+    macro_f_string_static_t_initialize_1("a/b//", 0, 6),
+    macro_f_string_static_t_initialize_1("./", 0, 2),
+    macro_f_string_static_t_initialize_1("./a", 0, 3),
+    macro_f_string_static_t_initialize_1("./a/", 0, 4),
+    macro_f_string_static_t_initialize_1("./a/b", 0, 5),
+    macro_f_string_static_t_initialize_1("./a/b/", 0, 6),
+    macro_f_string_static_t_initialize_1("./a/b//", 0, 7),
+    macro_f_string_static_t_initialize_1(".//", 0, 3),
+    macro_f_string_static_t_initialize_1(".//a", 0, 4),
+    macro_f_string_static_t_initialize_1(".//a/", 0, 5),
+    macro_f_string_static_t_initialize_1(".//a/b", 0, 6),
+    macro_f_string_static_t_initialize_1(".//a/b/", 0, 7),
+    macro_f_string_static_t_initialize_1(".//a/b//", 0, 8),
+    macro_f_string_static_t_initialize_1(".//a/\0b//", 0, 9),
+    macro_f_string_static_t_initialize_1(".\0//a/\0b/\0/", 0, 11),
+    macro_f_string_static_t_initialize_1("\0a", 0, 2),
+    macro_f_string_static_t_initialize_1("a\0", 0, 2),
+  };
+
+  const f_string_static_t expected[] = {
+    macro_f_string_static_t_initialize_1("", 0, 0),
+    macro_f_string_static_t_initialize_1("a", 0, 1),
+    macro_f_string_static_t_initialize_1("a", 0, 1),
+    macro_f_string_static_t_initialize_1("a/b", 0, 3),
+    macro_f_string_static_t_initialize_1("a/b", 0, 3),
+    macro_f_string_static_t_initialize_1("a/b", 0, 3),
+    macro_f_string_static_t_initialize_1(".", 0, 1),
+    macro_f_string_static_t_initialize_1("./a", 0, 3),
+    macro_f_string_static_t_initialize_1("./a", 0, 3),
+    macro_f_string_static_t_initialize_1("./a/b", 0, 5),
+    macro_f_string_static_t_initialize_1("./a/b", 0, 5),
+    macro_f_string_static_t_initialize_1("./a/b", 0, 5),
+    macro_f_string_static_t_initialize_1(".", 0, 1),
+    macro_f_string_static_t_initialize_1("./a", 0, 3),
+    macro_f_string_static_t_initialize_1("./a", 0, 3),
+    macro_f_string_static_t_initialize_1("./a/b", 0, 5),
+    macro_f_string_static_t_initialize_1("./a/b", 0, 5),
+    macro_f_string_static_t_initialize_1("./a/b", 0, 5),
+    macro_f_string_static_t_initialize_1("./a/b", 0, 5),
+    macro_f_string_static_t_initialize_1("./a/b", 0, 5),
+    macro_f_string_static_t_initialize_1("a", 0, 1),
+    macro_f_string_static_t_initialize_1("a", 0, 1),
+  };
+
+  f_string_dynamic_t path = f_string_dynamic_t_initialize;
+
+  for (uint8_t i = 0; i < 22; ++i) {
+
+    path.used = 0;
+
+    const f_status_t status = fl_path_clean(contents[i], &path);
+
+    assert_int_equal(status, F_okay);
+
+    // Assert_string_equal() is NULL terminated, so ensure NULL termination at end of path.used.
+    path.string[path.used] = 0;
+
+    assert_int_equal(expected[i].used, path.used);
+    assert_string_equal(expected[i].string, path.string);
+
+    memset(path.string, 0, path.used);
+  } // for
+
+  free((void *) path.string);
+}
+
+void test__fl_path_clean__root_paths(void **state) {
+
+  const f_string_static_t contents[] = {
+    macro_f_string_static_t_initialize_1("/", 0, 1),
+    macro_f_string_static_t_initialize_1("//", 0, 2),
+    macro_f_string_static_t_initialize_1("///", 0, 3),
+    macro_f_string_static_t_initialize_1("/a", 0, 2),
+    macro_f_string_static_t_initialize_1("//a", 0, 3),
+    macro_f_string_static_t_initialize_1("///a", 0, 4),
+    macro_f_string_static_t_initialize_1("/a/", 0, 3),
+    macro_f_string_static_t_initialize_1("//a/", 0, 4),
+    macro_f_string_static_t_initialize_1("///a/", 0, 5),
+    macro_f_string_static_t_initialize_1("/a/b", 0, 4),
+    macro_f_string_static_t_initialize_1("//a/b", 0, 5),
+    macro_f_string_static_t_initialize_1("///a/b", 0, 6),
+    macro_f_string_static_t_initialize_1("/a/b/", 0, 5),
+    macro_f_string_static_t_initialize_1("//a/b/", 0, 6),
+    macro_f_string_static_t_initialize_1("///a/b/", 0, 7),
+    macro_f_string_static_t_initialize_1("/a/b//", 0, 6),
+    macro_f_string_static_t_initialize_1("//a/b//", 0, 7),
+    macro_f_string_static_t_initialize_1("///a/b//", 0, 8),
+    macro_f_string_static_t_initialize_1("///a/\0b//", 0, 9),
+    macro_f_string_static_t_initialize_1("/\0//a/\0b\0//", 0, 11),
+    macro_f_string_static_t_initialize_1("\0/", 0, 2),
+    macro_f_string_static_t_initialize_1("/\0", 0, 2),
+  };
+
+  const f_string_static_t expected[] = {
+    macro_f_string_static_t_initialize_1("/", 0, 1),
+    macro_f_string_static_t_initialize_1("/", 0, 1),
+    macro_f_string_static_t_initialize_1("/", 0, 1),
+    macro_f_string_static_t_initialize_1("/a", 0, 2),
+    macro_f_string_static_t_initialize_1("/a", 0, 2),
+    macro_f_string_static_t_initialize_1("/a", 0, 2),
+    macro_f_string_static_t_initialize_1("/a", 0, 2),
+    macro_f_string_static_t_initialize_1("/a", 0, 2),
+    macro_f_string_static_t_initialize_1("/a", 0, 2),
+    macro_f_string_static_t_initialize_1("/a/b", 0, 4),
+    macro_f_string_static_t_initialize_1("/a/b", 0, 4),
+    macro_f_string_static_t_initialize_1("/a/b", 0, 4),
+    macro_f_string_static_t_initialize_1("/a/b", 0, 4),
+    macro_f_string_static_t_initialize_1("/a/b", 0, 4),
+    macro_f_string_static_t_initialize_1("/a/b", 0, 4),
+    macro_f_string_static_t_initialize_1("/a/b", 0, 4),
+    macro_f_string_static_t_initialize_1("/a/b", 0, 4),
+    macro_f_string_static_t_initialize_1("/a/b", 0, 4),
+    macro_f_string_static_t_initialize_1("/a/b", 0, 4),
+    macro_f_string_static_t_initialize_1("/a/b", 0, 4),
+    macro_f_string_static_t_initialize_1("/", 0, 1),
+    macro_f_string_static_t_initialize_1("/", 0, 1),
+  };
+
+  f_string_dynamic_t path = f_string_dynamic_t_initialize;
+
+  for (uint8_t i = 0; i < 22; ++i) {
+
+    path.used = 0;
+
+    const f_status_t status = fl_path_clean(contents[i], &path);
+
+    // Assert_string_equal() is NULL terminated, so ensure NULL termination at end of path.used.
+    if (status == F_okay) {
+      path.string[path.used] = 0;
+    }
+
+    assert_int_equal(status, F_okay);
+    assert_int_equal(expected[i].used, path.used);
+    assert_string_equal(expected[i].string, path.string);
+
+    memset(path.string, 0, path.used);
+  } // for
+
+  free((void *) path.string);
+}
+
+void test__fl_path_clean__tilde_remains(void **state) {
+
+  const f_string_static_t contents[] = {
+    macro_f_string_static_t_initialize_1("~", 0, 1),
+    macro_f_string_static_t_initialize_1("~/", 0, 2),
+    macro_f_string_static_t_initialize_1("~//", 0, 3),
+    macro_f_string_static_t_initialize_1("~a", 0, 2),
+    macro_f_string_static_t_initialize_1("a~", 0, 2),
+    macro_f_string_static_t_initialize_1("a~b", 0, 3),
+    macro_f_string_static_t_initialize_1("/~", 0, 2),
+    macro_f_string_static_t_initialize_1("//~", 0, 3),
+    macro_f_string_static_t_initialize_1("~ ", 0, 2),
+    macro_f_string_static_t_initialize_1("~ /", 0, 3),
+    macro_f_string_static_t_initialize_1("./~", 0, 3),
+    macro_f_string_static_t_initialize_1("./~a", 0, 4),
+    macro_f_string_static_t_initialize_1("./a~", 0, 4),
+    macro_f_string_static_t_initialize_1("./a~b", 0, 5),
+    macro_f_string_static_t_initialize_1("a/~/b", 0, 5),
+    macro_f_string_static_t_initialize_1("a/~b", 0, 4),
+    macro_f_string_static_t_initialize_1("a/~b/c", 0, 6),
+    macro_f_string_static_t_initialize_1("/a/~/b", 0, 6),
+    macro_f_string_static_t_initialize_1("/a/~b", 0, 5),
+    macro_f_string_static_t_initialize_1("/a/~b/c", 0, 7),
+    macro_f_string_static_t_initialize_1("//a/~/b", 0, 7),
+    macro_f_string_static_t_initialize_1("//a/~b", 0, 6),
+    macro_f_string_static_t_initialize_1("//a/~b/c", 0, 8),
+    macro_f_string_static_t_initialize_1("//a/~\0b/c", 0, 9),
+    macro_f_string_static_t_initialize_1("/\0/a/~\0b\0/c", 0, 11),
+    macro_f_string_static_t_initialize_1("\0~", 0, 2),
+    macro_f_string_static_t_initialize_1("~\0", 0, 2),
+  };
+
+  const f_string_static_t expected[] = {
+    macro_f_string_static_t_initialize_1("~", 0, 1),
+    macro_f_string_static_t_initialize_1("~", 0, 1),
+    macro_f_string_static_t_initialize_1("~", 0, 1),
+    macro_f_string_static_t_initialize_1("~a", 0, 2),
+    macro_f_string_static_t_initialize_1("a~", 0, 2),
+    macro_f_string_static_t_initialize_1("a~b", 0, 3),
+    macro_f_string_static_t_initialize_1("/~", 0, 2),
+    macro_f_string_static_t_initialize_1("/~", 0, 2),
+    macro_f_string_static_t_initialize_1("~ ", 0, 2),
+    macro_f_string_static_t_initialize_1("~ ", 0, 2),
+    macro_f_string_static_t_initialize_1("./~", 0, 3),
+    macro_f_string_static_t_initialize_1("./~a", 0, 4),
+    macro_f_string_static_t_initialize_1("./a~", 0, 4),
+    macro_f_string_static_t_initialize_1("./a~b", 0, 5),
+    macro_f_string_static_t_initialize_1("a/~/b", 0, 5),
+    macro_f_string_static_t_initialize_1("a/~b", 0, 4),
+    macro_f_string_static_t_initialize_1("a/~b/c", 0, 6),
+    macro_f_string_static_t_initialize_1("/a/~/b", 0, 6),
+    macro_f_string_static_t_initialize_1("/a/~b", 0, 5),
+    macro_f_string_static_t_initialize_1("/a/~b/c", 0, 7),
+    macro_f_string_static_t_initialize_1("/a/~/b", 0, 6),
+    macro_f_string_static_t_initialize_1("/a/~b", 0, 5),
+    macro_f_string_static_t_initialize_1("/a/~b/c", 0, 7),
+    macro_f_string_static_t_initialize_1("/a/~b/c", 0, 7),
+    macro_f_string_static_t_initialize_1("/a/~b/c", 0, 7),
+    macro_f_string_static_t_initialize_1("~", 0, 1),
+    macro_f_string_static_t_initialize_1("~", 0, 1),
+  };
+
+  f_string_dynamic_t path = f_string_dynamic_t_initialize;
+
+  for (uint8_t i = 0; i < 27; ++i) {
+
+    path.used = 0;
+
+    const f_status_t status = fl_path_clean(contents[i], &path);
+
+    assert_int_equal(status, F_okay);
+
+    // Assert_string_equal() is NULL terminated, so ensure NULL termination at end of path.used.
+    path.string[path.used] = 0;
+
+    assert_int_equal(expected[i].used, path.used);
+    assert_string_equal(expected[i].string, path.string);
+
+    memset(path.string, 0, path.used);
+  } // for
+
+  free((void *) path.string);
+}
+
+void test__fl_path_clean__parameter_checking(void **state) {
+
+  {
+    const f_status_t status = fl_path_clean(f_string_empty_s, 0);
+
+    assert_int_equal(status, F_status_set_error(F_parameter));
+  }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_1/fl_path/tests/unit/c/test-path-clean.h b/level_1/fl_path/tests/unit/c/test-path-clean.h
new file mode 100644 (file)
index 0000000..841f661
--- /dev/null
@@ -0,0 +1,55 @@
+/**
+ * FLL - Level 2
+ *
+ * Project: Path
+ * API Version: 0.6
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the fl_path project.
+ */
+#ifndef _TEST__FL_path_simple_h
+#define _TEST__FL_path_simple_h
+
+/**
+ * Test that function works with back paths (such as '../').
+ *
+ * @see fl_path_clean()
+ */
+extern void test__fl_path_clean__back_paths(void **state);
+
+/**
+ * Test that function leaves clean alone when the path is an empty string.
+ *
+ * @see fl_path_clean()
+ */
+extern void test__fl_path_clean__empty_stays_empty(void **state);
+
+/**
+ * Test that function works with present directory paths.
+ *
+ * @see fl_path_clean()
+ */
+extern void test__fl_path_clean__present_paths(void **state);
+
+/**
+ * Test that function works with root paths.
+ *
+ * @see fl_path_clean()
+ */
+extern void test__fl_path_clean__root_paths(void **state);
+
+/**
+ * Test that function returns the string without expanding the tilde.
+ *
+ * @see fl_path_clean()
+ */
+extern void test__fl_path_clean__tilde_remains(void **state);
+
+/**
+ * Test that parameter checking works as expected.
+ *
+ * @see fl_path_clean()
+ */
+extern void test__fl_path_clean__parameter_checking(void **state);
+
+#endif // _TEST__FL_path_simple_h
index ff0662233a255d43fb493a24a6d334a4ac14dc4a..7c1d60902ac1ccf428116c12a046df560991c456 100644 (file)
@@ -25,8 +25,15 @@ int main(void) {
     cmocka_unit_test(test__fl_path_canonical__root_paths),
     cmocka_unit_test(test__fl_path_canonical__tilde_remains),
 
+    cmocka_unit_test(test__fl_path_clean__back_paths),
+    cmocka_unit_test(test__fl_path_clean__empty_stays_empty),
+    cmocka_unit_test(test__fl_path_clean__present_paths),
+    cmocka_unit_test(test__fl_path_clean__root_paths),
+    cmocka_unit_test(test__fl_path_clean__tilde_remains),
+
     #ifndef _di_level_0_parameter_checking_
       cmocka_unit_test(test__fl_path_canonical__parameter_checking),
+      cmocka_unit_test(test__fl_path_clean__parameter_checking),
     #endif // _di_level_0_parameter_checking_
   };
 
index 505ba751b6385e76eadb639b26e489cda840b487..18a57ca65ce00905c589d82e0606b5a9e6472261 100644 (file)
@@ -29,6 +29,7 @@
 
 // Test includes.
 #include "test-path-canonical.h"
+#include "test-path-clean.h"
 
 #ifdef __cplusplus
 extern "C" {