Added UnitTest utility and removed unnecessary logging functions

This commit is contained in:
Leonardo committed 2019-06-26 01:32:44 -03:00
1 parent 41eebe546a
commit 176bbc66ad
3 files changed
+208 -66

No files matched your search

+1
View File
@@ -47,6 +47,7 @@
#include "utl/foreach.h"
#include "utl/log.h"
#include "utl/test.h"
#include "utl/timer.h"
#endif /* CMC_MACRO_COLLECTIONS */
+31 -66
View File
@@ -11,7 +11,10 @@
/**
* Simple logging macros
* You can toggle colors defining the macro CMC_LOG_COLOR but be sure that
* your terminal supports ANSI color escape codes
* your terminal supports ANSI color escape codes.
*
* You can customize the logging utility by accessing cmc_log_config and
* directly modifying its values to better suit your needs.
*/
/**
@@ -42,21 +45,6 @@
* ERROR - 5
* FATAL - 6
*
* Functions API
*
* void cmc_log_tlevel(int level)
* Set level for the Terminal Output to stderr.
* void cmc_log_flevel(int level)
* Set level for the File Output to FILE pointer.
* void cmc_log_tenable(bool enabled)
* Enables or disables Terminal Output to stderr.
* void cmc_log_fenable(bool enabled)
* Enables or disables File Output.
* void cmc_log_file(FILE *file)
* Set a file for writing the logging messages to it.
* void cmc_log_set(bool enabled)
* Sets on or off all the logging messages.
*
* How the Log Level is calculated
*
* - If the log level is 0 all logs are enabled.
@@ -76,8 +64,13 @@
#include <stdarg.h>
#include <stdbool.h>
static const char *names[] = {"TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"};
static const char *color[] = {"\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m"};
static const char *cmc_log_names[] = {"TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"};
#ifdef CMC_LOG_COLOR
static const char *cmc_log_color[] = {"\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m"};
#endif
static struct
{
@@ -87,9 +80,10 @@ static struct
bool fenabled; /* File Output Enabled */
FILE *file; /* File for Output */
bool enabled; /* Logging enabled */
} log_config = {0, 0, true, true, NULL, true};
typedef enum log_type_e
} cmc_log_config = {0, 0, true, true, NULL, true};
typedef enum cmc_log_type_e
{
LOG_TRACE = 1,
LOG_DEBUG = 2,
@@ -97,7 +91,8 @@ typedef enum log_type_e
LOG_WARN = 4,
LOG_ERROR = 5,
LOG_FATAL = 6
} log_type;
} cmc_log_type;
#define log_trace(fmt, ...) cmc_log(LOG_TRACE, __FILE__, __func__, __LINE__, fmt, __VA_ARGS__)
#define log_debug(fmt, ...) cmc_log(LOG_DEBUG, __FILE__, __func__, __LINE__, fmt, __VA_ARGS__)
@@ -106,46 +101,16 @@ typedef enum log_type_e
#define log_error(fmt, ...) cmc_log(LOG_ERROR, __FILE__, __func__, __LINE__, fmt, __VA_ARGS__)
#define log_fatal(fmt, ...) cmc_log(LOG_FATAL, __FILE__, __func__, __LINE__, fmt, __VA_ARGS__)
static void cmc_log_tlevel(int terminal_level)
static void cmc_log(cmc_log_type log, const char *filename, const char *funcname, int line, const char *fmt, ...)
{
log_config.tlevel = terminal_level;
}
static void cmc_log_flevel(int file_level)
{
log_config.flevel = file_level;
}
static void cmc_log_tenable(bool enabled)
{
log_config.tenabled = enabled;
}
static void cmc_log_fenable(bool enabled)
{
log_config.fenabled = enabled;
}
static void cmc_log_file(FILE *file)
{
log_config.file = file;
}
static void cmc_log_set(bool enabled)
{
log_config.enabled = enabled;
}
static void cmc_log(log_type log, const char *filename, const char *funcname, int line, const char *fmt, ...)
{
if (!log_config.enabled)
if (!cmc_log_config.enabled)
return;
if (log_config.tenabled)
if (cmc_log_config.tenabled)
{
if (log_config.tlevel < 0 && ((int)log * -1) < log_config.tlevel)
if (cmc_log_config.tlevel < 0 && ((int)log * -1) < cmc_log_config.tlevel)
return;
else if (log_config.tlevel > 0 && (int)log < log_config.tlevel)
else if (cmc_log_config.tlevel > 0 && (int)log < cmc_log_config.tlevel)
return;
int i = (int)log - 1;
@@ -156,14 +121,14 @@ static void cmc_log(log_type log, const char *filename, const char *funcname, in
char time[16];
time[strftime(time, sizeof(time), "%H:%M:%S", lt)] = '\0';
#if defined(CMC_LOG_COLOR)
#ifdef CMC_LOG_COLOR
fprintf(stderr,
"%s %s%5s\x1b[0m \x1b[90m%s at %s:%d:\x1b[0m ",
time, color[i], names[i], filename, funcname, line);
time, cmc_log_color[i], cmc_log_names[i], filename, funcname, line);
#else
fprintf(stderr,
"%s %5s %s at %s:%d: ",
time, names[i], filename, funcname, line);
time, cmc_log_names[i], filename, funcname, line);
#endif
va_list args;
@@ -175,11 +140,11 @@ static void cmc_log(log_type log, const char *filename, const char *funcname, in
fflush(stderr);
}
if (log_config.file && log_config.fenabled)
if (cmc_log_config.file && cmc_log_config.fenabled)
{
if (log_config.flevel < 0 && ((int)log * -1) < log_config.flevel)
if (cmc_log_config.flevel < 0 && ((int)log * -1) < cmc_log_config.flevel)
return;
else if (log_config.flevel > 0 && (int)log < log_config.flevel)
else if (cmc_log_config.flevel > 0 && (int)log < cmc_log_config.flevel)
return;
int i = (int)log - 1;
@@ -190,15 +155,15 @@ static void cmc_log(log_type log, const char *filename, const char *funcname, in
char time[32];
time[strftime(time, sizeof(time), "%Y-%m-%d %H:%M:%S", lt)] = '\0';
fprintf(log_config.file, "%s %5s %s at %s:%d: ", time, names[i], filename, funcname, line);
fprintf(cmc_log_config.file, "%s %5s %s at %s:%d: ", time, cmc_log_names[i], filename, funcname, line);
va_list file_args;
va_start(file_args, fmt);
vfprintf(log_config.file, fmt, file_args);
vfprintf(cmc_log_config.file, fmt, file_args);
va_end(file_args);
fprintf(log_config.file, "\n");
fflush(log_config.file);
fprintf(cmc_log_config.file, "\n");
fflush(cmc_log_config.file);
}
}
+176
View File
@@ -0,0 +1,176 @@
/**
* test.h
*
* Creation Date: 26/06/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
/**
* Simple Unit Test Utility
*
* CMC_CREATE_UNIT
* Create a UnitTest
* Parameters:
* - UNAME : UnitTest name (const char *)
* - VERBOSE : Print PASSED / FAILED messages if true (bool)
* - BODY : Body containing all tests related to this UnitTest
*
* CMC_CREATE_TEST
* Create a Test inside a UnitTest.
* Parameters:
* - TNAME : Test name (const char *)
* - BODY : Block of code containing a specific test
* Inside the BODY use the following macros:
* - CMC_TEST_PASS
* Pass current test.
* - CMC_TEST_FAIL
* Fail current test.
* - CMC_TEST_PASS_ELSE_FAIL
* If given expression is true, pass current test, else fail.
* - CMC_TEST_ABORT
* Abort current unit test and displays error message. All tests
* after the abort won't be called.
* All of these macros can only be called once per test.
*
* CMC_TEST_COLOR
* Define this macro to allow colored output.
*/
#ifndef CMC_TEST_H
#define CMC_TEST_H
#include "timer.h"
#include <inttypes.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef CMC_TEST_COLOR
static const char *cmc_test_color[] = {"\x1b[32m", "\x1b[31m", "\x1b[35m"};
#endif
typedef struct cmc_test_info_s
{
uintmax_t total;
uintmax_t passed;
uintmax_t failed;
bool aborted;
bool verbose;
} cmc_test_info;
/* Logging function */
static void cmc_test_log(const char *unit_name, const char *current_test, bool aborted, bool passed)
{
if (aborted)
{
#ifdef CMC_TEST_COLOR
printf("UNIT_TEST %s %sABORTED\x1b[0m AT %s\n",
unit_name,
cmc_test_color[2],
current_test);
#else
printf("UNIT_TEST %s ABORTED at %s\n", unit_name, current_test);
#endif
}
else
{
#ifdef CMC_TEST_COLOR
printf("Test from %s %s%7s\x1b[0m %s\n",
unit_name,
passed ? cmc_test_color[0] : cmc_test_color[1],
passed ? "PASSED" : "FAILED",
current_test);
#else
printf("Test from %s %7s %s\n", unit_name, passed ? "PASSED" : "FAILED", current_test);
#endif
}
}
#define CMC_CREATE_UNIT(UNAME, VERBOSE, BODY) \
void UNAME(void) \
{ \
const char *unit_name = #UNAME; \
const char *current_test = NULL; \
\
cmc_test_info tinfo = {0}; \
timer_t timer = {0}; \
\
tinfo.verbose = VERBOSE; \
\
/* Tests */ \
TIMER_START(timer); \
BODY; \
TIMER_STOP(timer); \
TIMER_CALC(timer); \
\
unittest_abort: \
if (tinfo.aborted) \
{ \
cmc_test_log(unit_name, current_test, true, false); \
} \
\
printf("+--------------------------------------------------+\n"); \
printf("| Unit Test Report : %-30s|\n", unit_name); \
printf("| TOTAL : %10" PRIuMAX " |\n", tinfo.total); \
printf("| PASSED : %10" PRIuMAX " |\n", tinfo.passed); \
printf("| FAILED : %10" PRIuMAX " |\n", tinfo.failed); \
printf("| |\n"); \
printf("| Total Unit Test Runtime : %9.0f milliseconds |\n", timer.result); \
printf("+--------------------------------------------------+\n"); \
}
#define CMC_CREATE_TEST(TNAME, BODY) \
do \
{ \
current_test = #TNAME; \
\
tinfo.total += 1; \
\
BODY; \
\
} while (0);
#define CMC_TEST_PASS() \
do \
{ \
tinfo.passed += 1; \
if (tinfo.verbose) \
cmc_test_log(unit_name, current_test, false, true); \
\
} while (0)
#define CMC_TEST_FAIL() \
do \
{ \
tinfo.failed += 1; \
if (tinfo.verbose) \
cmc_test_log(unit_name, current_test, false, false); \
\
} while (0)
#define CMC_TEST_PASS_ELSE_FAIL(EXPRESSION) \
do \
{ \
if (EXPRESSION) \
CMC_TEST_PASS(); \
else \
CMC_TEST_FAIL(); \
\
} while (0)
#define CMC_TEST_ABORT() \
do \
{ \
\
tinfo.aborted = true; \
tinfo.total -= 1; \
goto unittest_abort; \
\
} while (0)
#endif /* CMC_TEST_H */