From ff0f8b35dd4e3f8cf5dd329fd253c7308a987d74 Mon Sep 17 00:00:00 2001
From: "dario.genga" <dario.genga@etu.hesge.ch>
Date: Sat, 18 Jun 2022 19:10:59 +0200
Subject: [PATCH] Add tests for values_utils

---
 .gitignore          |   1 +
 makefile            |   4 ++
 values_utils.c      |   2 +-
 values_utils_test.c | 154 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 160 insertions(+), 1 deletion(-)
 create mode 100644 values_utils_test.c

diff --git a/.gitignore b/.gitignore
index b97ac13..90da48c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -79,6 +79,7 @@ dkms.conf
 
 # Custom gitignore for project
 main
+tests
 output_data.txt
 cmake-build-debug
 .idea
\ No newline at end of file
diff --git a/makefile b/makefile
index bf03ed3..e564182 100644
--- a/makefile
+++ b/makefile
@@ -4,6 +4,10 @@ CC=gcc -Wall -Wextra -g
 main: files_utils.o values_utils.o kmeans.o main.o
 	$(CC) $^ -fsanitize=address -fsanitize=leak -o $@ $(LIB)
 
+run_tests: tests
+	./$<
+tests: values_utils_test.c values_utils.o
+	$(CC) $^ -fsanitize=address -fsanitize=leak -o $@ $(LIB)
 files_utils.o: files_utils.c files_utils.h
 	$(CC) -c $< $(LIB)
 values_utils.o: values_utils.c values_utils.h
diff --git a/values_utils.c b/values_utils.c
index c4a811d..1c4e8ee 100644
--- a/values_utils.c
+++ b/values_utils.c
@@ -41,7 +41,7 @@ float compute_chebyshev_distance(float* p1, float* p2, size_t dimensions) {
     float result = 0;
 
     for (size_t i = 0; i < dimensions; i++) {
-        int abs_diff = fabs(p1[i] - p2[i]);
+        float abs_diff = fabs(p1[i] - p2[i]);
         if (abs_diff > result) {
             result = abs_diff;
         }
diff --git a/values_utils_test.c b/values_utils_test.c
new file mode 100644
index 0000000..043c081
--- /dev/null
+++ b/values_utils_test.c
@@ -0,0 +1,154 @@
+// Project : K-means
+// Author : Dario GENGA
+
+// Required include
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+// "Personal" include
+#include "values_utils.h"
+
+#define FLOAT_EPSILON 1e-6
+
+// For tests display
+typedef struct _test_result {
+    bool passed;
+    const char *name;
+} test_result;
+
+typedef test_result (*unit_test_t)(void);
+
+void print_in_color(char *color, char *text) {
+    printf("\033%s", color);
+    printf("%s", text);
+    printf("\033[0m");
+}
+
+void print_in_red(char *text) {
+    print_in_color("[0;31m", text);
+}
+
+void print_in_green(char *text) {
+    print_in_color("[0;32m", text);
+}
+
+// Custom utility methods
+
+bool float_eq(float a, float b) {
+    return fabs(a - b) < FLOAT_EPSILON;
+}
+
+const float initial_x[] = {1, -5.25, -3.3};
+const float initial_y[] = {5, 5.25f, -2.2};
+const uint32_t nb_tests = sizeof(initial_x) / sizeof(float);
+
+// tests methods
+test_result t_compute_euclidean_distance_0() {
+    bool passed = true;
+
+    float expected_one_dimension_val[3] = {4, 10.5, 1.1};
+    float expected_val = 11.289818;
+    float t_val = 0;
+
+    // Multiple one dimension tests
+    for (uint32_t i = 0; i < nb_tests; i++) {
+        t_val = compute_euclidean_distance((float*)&(initial_x)[i], (float*)&(initial_y)[i], 1);
+        if (!float_eq(t_val, expected_one_dimension_val[i])) {
+            passed = false;
+            break;
+        }
+    }
+
+    // Test with 3 dimensions
+    t_val = compute_euclidean_distance((float*)initial_x, (float*)initial_y, 3);
+    if (!float_eq(t_val, expected_val)) {
+        passed = false;
+    }
+
+    return (test_result) {.passed = passed,
+            .name = "Test compute_euclidean_distance"};
+}
+
+test_result t_compute_manhattan_distance_0() {
+    bool passed = true;
+
+    float expected_one_dimension_val[3] = {4, 10.5, 1.1};
+    float expected_val = 15.6;
+    float t_val = 0;
+
+    // Multiple one dimension tests
+    for (uint32_t i = 0; i < nb_tests; i++) {
+        t_val = compute_manhattan_distance((float*)&(initial_x)[i], (float*)&(initial_y)[i], 1);
+        if (!float_eq(t_val, expected_one_dimension_val[i])) {
+            passed = false;
+            break;
+        }
+    }
+
+    // Test with 3 dimensions
+    t_val = compute_manhattan_distance((float*)initial_x, (float*)initial_y, 3);
+    if (!float_eq(t_val, expected_val)) {
+        passed = false;
+    }
+
+    return (test_result) {.passed = passed,
+            .name = "Test compute_euclidean_distance"};
+}
+
+test_result t_compute_chebyshev_distance_0() {
+    bool passed = true;
+
+    float expected_one_dimension_val[3] = {4, 10.5, 1.1};
+    float expected_val = 10.5;
+    float t_val = 0;
+
+    // Multiple one dimension tests
+    for (uint32_t i = 0; i < nb_tests; i++) {
+        t_val = compute_chebyshev_distance((float*)&(initial_x)[i], (float*)&(initial_y)[i], 1);
+        if (!float_eq(t_val, expected_one_dimension_val[i])) {
+            passed = false;
+            break;
+        }
+    }
+
+    // Test with 3 dimensions
+    t_val = compute_chebyshev_distance((float*)initial_x, (float*)initial_y, 3);
+    if (!float_eq(t_val, expected_val)) {
+        passed = false;
+    }
+
+    return (test_result) {.passed = passed,
+            .name = "Test compute_euclidean_distance"};
+}
+
+// Add or remove the test function name here
+const unit_test_t tests[] = {
+        t_compute_euclidean_distance_0,
+        t_compute_manhattan_distance_0,
+        t_compute_chebyshev_distance_0
+};
+
+int main() {
+    uint32_t nb_tests = sizeof(tests) / sizeof(unit_test_t);
+    char message[256];
+    bool all_passed = true;
+
+    for (uint32_t i = 0; i < nb_tests; i++) {
+        printf("Running test n°%d: ...\n", i);
+        test_result r = tests[i]();
+        if (r.passed) {
+            sprintf(message, "\t- %s : OK", r.name);
+            print_in_green(message);
+        } else {
+            all_passed = false;
+            sprintf(message, "\t- %s : FAILED", r.name);
+            print_in_red(message);
+        }
+        printf("\n");
+    }
+    if (all_passed)
+        print_in_green("\nTests suite result : OK\n");
+    else
+        print_in_red("\nTests suite result : FAILED\n");
+}
\ No newline at end of file
-- 
GitLab