lib

morphux C utility library
Log | Files | Refs | Submodules | README | LICENSE | git clone https://git.ne02ptzero.me/git/lib

commit 8b26ce1d4940e09a52925eab6ac36534fd3b5504
parent 8398f87985560e5c9c0a1a16cb196acd314ba7cc
Author: Ne02ptzero <louis@ne02ptzero.me>
Date:   Thu, 19 Jan 2017 15:56:23 +0100

Add(Tests): Add test functions:

Some fixes in list too

Diffstat:
MMakefile | 2+-
Minc/m_list.h | 1+
Ainc/m_test.h | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Minc/morphux.h | 2++
Msrc/m_list.c | 35++++++++++++++++++++++++++++++-----
Asrc/m_test.c | 164+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 258 insertions(+), 6 deletions(-)

diff --git a/Makefile b/Makefile @@ -17,7 +17,7 @@ NAME= libmorphux.a CC = gcc LIB = ar -CFLAGS = -Wall -Wextra -Werror -I inc/ -std=c99 +CFLAGS = -Wall -Wextra -Werror -I inc/ -std=c99 -g -O3 LFLAGS = -cq SRCS = $(wildcard src/*.c) OBJS = $(SRCS:%.c=%.o) diff --git a/inc/m_list.h b/inc/m_list.h @@ -57,5 +57,6 @@ mlist_t *list_insert_after(mlist_t *org, mlist_t *ptr, void *member, u32_t size mlist_t *list_insert_before(mlist_t *org, mlist_t *ptr, void *member, u32_t size); u32_t list_size(mlist_t *list); mlist_t *list_free(mlist_t *list, int (*free_fn)(void *member)); +void *list_get(mlist_t *list, void *member, size_t size); #endif diff --git a/inc/m_test.h b/inc/m_test.h @@ -0,0 +1,60 @@ +/*********************************** LICENSE **********************************\ +* Copyright 2017 Morphux * +* * +* Licensed under the Apache License, Version 2.0 (the "License"); * +* you may not use this file except in compliance with the License. * +* You may obtain a copy of the License at * +* * +* http://www.apache.org/licenses/LICENSE-2.0 * +* * +* Unless required by applicable law or agreed to in writing, software * +* distributed under the License is distributed on an "AS IS" BASIS, * +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * +* See the License for the specific language governing permissions and * +* limitations under the License. * +\******************************************************************************/ + +#ifndef M_TEST_H +# define M_TEST_H + +# include <stdio.h> +# include <unistd.h> +# include <m_list.h> +# include <m_print.h> + +typedef struct s_test { + char *(*fn_test)(void); + char *group; + char *name; +} mtest_t; + +typedef struct s_test_results { + u32_t success; + u32_t failed; + u32_t total; +} mtest_results_t; + + +/* Defines */ +# define TEST_SUCCESS 0x0 +# define TITLE_LEN 80 + +# define TEST(name) char *test_##name(void) +# define reg_test(group, name) register_test(group, &test_##name, #name); +# define TEST_ASSERT(condition, error_name) {\ + if (!condition) {\ + char *ret = NULL; \ + asprintf(&ret, "\t%s: Test: '%s', File %s:%d", error_name, #condition, __FILE__, __LINE__);\ + return ret;\ + }\ +} + +/* Functions */ +static void title(char *s); +void register_test(char *group, char *(*fn_test)(void), char *name); +mtest_results_t test_group(char *group); +void test_all(void); +void test_free(void); +static int single_test_free(void *ptr); + +#endif /* M_TEST_H */ diff --git a/inc/morphux.h b/inc/morphux.h @@ -21,5 +21,7 @@ # include <m_print.h> # include <m_args.h> # include <m_infos.h> +# include <m_list.h> +# include <m_test.h> #endif /* MORPHUX_H */ diff --git a/src/m_list.c b/src/m_list.c @@ -215,15 +215,40 @@ u32_t list_size(mlist_t *list) { * \return If the list has been entirely freed, this function will return NULL */ mlist_t *list_free(mlist_t *list, int (*free_fn)(void *member)) { - mlist_t *tmp; + mlist_t *tmp = list, *tmp2; - for (tmp = list; tmp != NULL; tmp = tmp->next) { - if (free_fn(tmp->member) != 0) { + while (tmp != NULL) { + tmp2 = tmp->next; + if (free_fn != NULL && free_fn(tmp->member) == 0) { + return tmp; + } else { free(tmp->member); free(tmp); - } else { - return tmp; } + tmp = tmp2; + } + return NULL; +} + +/*! + * \brief Search a member in a list + * \param list List head + * \param member Member to search + * \param size Size of the member + * + * Search member in list. + * If member is found, return a pointer to it + * If not, NULL is returned + */ +void *list_get(mlist_t *list, void *member, size_t size) { + mlist_t *tmp; + void *ptr; + + if (list == NULL) + return NULL; + list_for_each(list, tmp, ptr) { + if (memcmp(ptr, member, size) == 0 && (size == tmp->size)) + return ptr; } return NULL; } diff --git a/src/m_test.c b/src/m_test.c @@ -0,0 +1,164 @@ +/*********************************** LICENSE **********************************\ +* Copyright 2017 Morphux * +* * +* Licensed under the Apache License, Version 2.0 (the "License"); * +* you may not use this file except in compliance with the License. * +* You may obtain a copy of the License at * +* * +* http://www.apache.org/licenses/LICENSE-2.0 * +* * +* Unless required by applicable law or agreed to in writing, software * +* distributed under the License is distributed on an "AS IS" BASIS, * +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * +* See the License for the specific language governing permissions and * +* limitations under the License. * +\******************************************************************************/ + +#include <m_test.h> + +static mlist_t *tests = NULL; + +/*! + * \brief Print a title + * \param s Title name + */ +static void title(char *s) { + u8_t len = TITLE_LEN; + int i; + + len -= strlen(s); + for (i = 0; i < len / 2; i++, write(1, "=", 1)) + ; + write(1, " ", 1); + write(1, s, strlen(s)); + write(1, " ", 1); + for (; i < len; i++, write(1, "=", 1)); + write(1, "\n", 1); +} + +/*! + * \brief Register a test + * \param group Group name + * \param fn_test Test function + * \param name Test name + * + * \note Do not call this function directly, use test_reg macro instead. + */ +void register_test(char *group, char *(*fn_test)(void), char *name) { + mtest_t *ptr; + + /* Allocate test */ + ptr = malloc(sizeof(mtest_t)); + assert(ptr); + ptr->group = malloc(strlen(group) + 1); + ptr->name = malloc(strlen(name) + 1); + assert(ptr->group && ptr->name); + + /* Copy name and group */ + memcpy(ptr->group, group, strlen(group)); + memcpy(ptr->name, name, strlen(name)); + ptr->name[strlen(name)] = 0; + ptr->group[strlen(group)] = 0; + assert(ptr->group && ptr->name); + ptr->fn_test = fn_test; + + /* Add to the list of tests */ + list_add(tests, ptr, sizeof(mtest_t)); + free(ptr); +} + +/*! + * \brief Test an entire group of tests + * \param group Group name + */ +mtest_results_t test_group(char *group) { + mlist_t *tmp; + mtest_t *ptr; + mtest_results_t res; + u32_t tab; + char *s_tmp; + + res.total = res.success = res.failed = 0; + title(group); + + /* Iterate over each test */ + list_for_each(tests, tmp, ptr) { + if (strcmp(ptr->group, group) == 0) { + res.total++; + m_info("Testing %s ...", ptr->name); + + for (tab = strlen(ptr->name); tab < TITLE_LEN - 18; + tab++, printf(" ")) + ; + + if ((s_tmp = ptr->fn_test()) != TEST_SUCCESS) { + printf("[ \033[1;31mKO\033[0m ]\n"); + m_warning("\033[0;37m%s\033[0m\n", s_tmp); + free(s_tmp); + res.failed++; + } else { + printf("[ \033[1;32mOK\033[0m ]\n"); + res.success++; + } + } + } + + if (res.total == 0) { + m_warning("Could not find any registered tests in %s group.\n", group); + } else { + m_info("Group Results: %d%% (%d/%d)\n", + (res.success * 100) / res.total, res.success, res.total); + } + return res; +} + +/*! + * \brief Test all registered tests + */ +void test_all(void) { + mlist_t *tmp, *groups = NULL; + mtest_t *ptr; + mtest_results_t res; + u32_t total = 0, success = 0, failed = 0; + + list_for_each(tests, tmp, ptr) { + if (list_get(groups, ptr->group, strlen(ptr->group)) == NULL) { + res = test_group(ptr->group); + total += res.total; + success += res.success; + failed += res.failed; + list_add(groups, ptr->group, strlen(ptr->group)); + } + } + + list_free(groups, NULL); + + if (total == 0) + m_warning("No tests registered, skipping.\n"); + else { + printf("\n"); + m_info("Results: %d%% (%d/%d)\n", (success * 100) / total, success, total); + } +} + +/*! + * \brief Free all the test + */ +void test_free(void) { + list_free(tests, &single_test_free); + tests = NULL; +} + +/*! + * \brief Free a single test + * \note Used in test_free, as a list_free callback + */ +static int single_test_free(void *ptr) { + mtest_t *tmp = ptr; + + if (ptr) { + free(tmp->group); + free(tmp->name); + } + return 1; +}