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