Added UnitTest utility and removed unnecessary logging functions
This commit is contained in:
1 parent
41eebe546a
commit
176bbc66ad
3 files changed
+208
-66
No files matched your search
@@ -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
@@ -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
@@ -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 */
|
||||
Reference in new issue
Block a user