feat: (test) add test module

This commit is contained in:
thetek 2023-02-11 16:25:24 +01:00
parent 66f45c9152
commit 1f07e35af5
5 changed files with 164 additions and 28 deletions

View File

@ -31,7 +31,7 @@ strtrim (char *str)
* original string.
*/
char *
strtriml (const char *str)
strtriml (char *str)
{
while (*str && isspace (*str))
str++;

View File

@ -4,7 +4,7 @@
#include <stddef.h>
char *strtrim (char *str); /* trim whitespace of a cstring (both beginning and end) */
char *strtriml (const char *str); /* trim whitespace of a cstring on the left (beginning of string). */
char *strtriml (char *str); /* trim whitespace of a cstring on the left (beginning of string). */
size_t strtrimr (char *str); /* trim whitespace of a cstring on the right (end of string) */
#endif // CUTILS_CSTR_H_

39
lib/inc/test.h Normal file
View File

@ -0,0 +1,39 @@
#ifndef CUTILS_TEST_H_
#define CUTILS_TEST_H_
#include <stdbool.h>
#include <stddef.h>
#define test_add(suite, success_and_assertion, name) test_suite_add (suite, success_and_assertion, name, __FILE__, __LINE__)
#define test_assert_op(a, op, b) ((a) op (b)), (#a " " #op " " #b)
#define test_assert(a) ((bool) a), (#a)
typedef struct
{
size_t success;
size_t failure;
} test_results_t;
typedef test_results_t (*test_entry_func_t) (void);
typedef struct
{
test_entry_func_t *entries;
size_t entries_len;
size_t entries_cap;
} test_group_t;
typedef struct
{
test_results_t results;
} test_suite_t;
test_group_t test_group_new (void);
void test_group_free (test_group_t *group);
void test_group_add (test_group_t *group, test_entry_func_t func);
test_results_t test_group_run (test_group_t *group);
test_suite_t test_suite_new (void);
void test_suite_add (test_suite_t *suite, bool success, const char *assertion, const char *name, const char *file, size_t line);
test_results_t test_suite_get_results (test_suite_t *suite);
#endif // CUTILS_TEST_H_

93
lib/test.c Normal file
View File

@ -0,0 +1,93 @@
#include "test.h"
#include <stdio.h>
#include <stdlib.h>
#include "log.h"
#define TEST_GROUP_ENTRIES_ALLOC 16
test_group_t
test_group_new (void)
{
test_group_t group;
group = (test_group_t) {0};
if ((group.entries = malloc ((sizeof *(group.entries)) * TEST_GROUP_ENTRIES_ALLOC)) == NULL)
{
log_error ("failed to allocate memory\n");
exit (EXIT_FAILURE);
}
group.entries[0] = NULL;
group.entries_cap = TEST_GROUP_ENTRIES_ALLOC;
return group;
}
void
test_group_free (test_group_t *group)
{
free (group->entries);
}
void
test_group_add (test_group_t *group, test_entry_func_t func)
{
if (group->entries_len == group->entries_cap - 1)
{
group->entries_cap += TEST_GROUP_ENTRIES_ALLOC;
if ((group->entries = realloc (group->entries, (sizeof *(group->entries)) * group->entries_cap)) == NULL)
{
log_error ("failed to allocate memory\n");
exit (EXIT_FAILURE);
}
}
group->entries[group->entries_len] = func;
group->entries_len += 1;
group->entries[group->entries_len] = NULL;
}
test_results_t
test_group_run (test_group_t *group)
{
test_results_t total_result, result;
size_t i;
total_result = (test_results_t) {0};
for (i = 0; i < group->entries_len; i++)
{
result = group->entries[i]();
total_result.success += result.success;
total_result.failure += result.failure;
}
if (total_result.failure == 0)
log_ok ("all tests successful (%zu tests in %zu sections)\n", total_result.success, group->entries_len);
else
log_error ("tests unsuccessful (%zu tests in %zu sections, out of which %zu successful and %zu failures)\n", total_result.success + total_result.failure, group->entries_len, total_result.success, total_result.failure);
return total_result;
}
test_suite_t
test_suite_new (void)
{
return (test_suite_t) {0};
}
void
test_suite_add (test_suite_t *suite, bool success, const char *assertion, const char *name, const char *file, size_t line)
{
if (success)
suite->results.success += 1;
else
{
suite->results.failure += 1;
log_print_fl (LOG_LEVEL_ERROR, file, line, "test '%s' (assertion '%s') failed\n", name, assertion);
}
}
test_results_t
test_suite_get_results (test_suite_t *suite)
{
return suite->results;
}

View File

@ -7,37 +7,41 @@
#define CUTILS_DEBUG_TRACE
#include "debug.h"
#include "log.h"
#include "test.h"
test_results_t
test_cstr (void)
{
test_suite_t suite;
size_t len;
suite = test_suite_new ();
char s[] = " Hello, World!\n ";
len = strtrimr (s);
test_add (&suite, test_assert_op (len, ==, 17), "strtrimr return value");
test_add (&suite, test_assert_op (strlen (s), ==, 17), "strtrimr length");
char *sn = strtriml (s);
test_add (&suite, test_assert_op (sn, ==, s + 4), "strtriml pointer");
test_add (&suite, test_assert_op (strlen (sn), ==, 13), "strtriml length");
char s2[] = " Hello, World!\n ";
sn = strtrim (s2);
test_add (&suite, test_assert_op (sn, ==, s2 + 4), "strtrim pointer");
test_add (&suite, test_assert_op (strlen (s2), ==, 17), "strtrim original pointer length");
test_add (&suite, test_assert_op (strlen (sn), ==, 13), "strtrim new pointer length");
return test_suite_get_results (&suite);
}
int
main (void)
{
char *ptr;
size_t len;
test_group_t group;
ptr = malloc ((sizeof *ptr) * 1);
ptr = realloc (ptr, (sizeof *ptr) * 4096);
ptr = realloc (ptr, (sizeof *ptr) * 524288);
free (ptr);
log_print (LOG_LEVEL_ERROR, "error! %s\n", "string fmt");
log_print (LOG_LEVEL_WARNING, "warning! %c\n", 'c');
log_print (LOG_LEVEL_INFO, "info! %d\n", 42);
log_print (LOG_LEVEL_OK, "okay! %#x\n", 69);
log_print (LOG_LEVEL_DEBUG, "debug! %04.04f\n", 13.37);
log_print_fl (LOG_LEVEL_OK, __FILE__, __LINE__, "file and line\n");
char s[] = " Hello, World!\n ";
len = strtrimr (s);
assert (len == 17);
assert (strlen (s) == 17);
char *sn = strtriml (s);
assert (sn == s + 4);
assert (strlen (sn) == 13);
char s2[] = " Hello, World!\n ";
sn = strtrim (s2);
assert (strlen (s2) == 17);
assert (sn == s2 + 4);
assert (strlen (sn) == 13);
group = test_group_new ();
test_group_add (&group, test_cstr);
test_group_run (&group);
test_group_free (&group);
return EXIT_SUCCESS;
}