added testing framework

generic-project-skeleton
Avril 3 years ago
parent 672502449b
commit 701601f5cd
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -5,7 +5,7 @@ PROJECT=naka
DESCRIPTION="Find a file within another file"
AUTHOR=Avril (Flanchan) <flanchan@cumallover.me>
SRC_C = $(wildcard src/*.c)
SRC_C = $(wildcard src/*.c) $(wildcard src/tests/*.c)
SRC_CXX = $(wildcard src/*.cpp)
INCLUDE=include
@ -50,7 +50,7 @@ debug: | dirs $(PROJECT)-debug
# Targets
dirs:
@mkdir -p obj/c{,xx}/src
@mkdir -p obj/c{,xx}/src{,/tests}
obj/c/%.o: %.c
$(CC) -c $< $(CFLAGS) -o $@ $(LDFLAGS)

@ -9,6 +9,7 @@
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <assert.h>
// Attribute macros
@ -84,6 +85,8 @@ _mixin void _drain_val(void* x, ...) { IGNORE(x); }
// Assertions
#define assert_msg(expr, ...) ( (expr) ? 1 : FATAL(__VA_ARGS__))
#ifdef DEBUG
#define debug_assert(x) assert((x))
#elif defined(_EVAL_DEBUG_ONLY_STMTS)
@ -136,8 +139,10 @@ static_assert_eq(bswap(bswap(128lu)), 128, "bswap128 (lu) failed (3)");
#ifdef DEBUG
#define TRACE(msg, ...) TRACEx("trace", msg, ## __VA_ARGS__)
#define dprintf(msg, ...) TRACEx("debug", msg, ## __VA_ARGS__)
#elif defined(_EVAL_DEBUG_ONLY_STMTS)
#define TRACE(msg, ...) _drain(msg, ## __VA_ARGS__)
#define dprintf(msg, ...) _drain(msg, ## __VA_ARGS__)
#else
#define TRACE(msg, ...) _no_op
#endif
@ -147,6 +152,19 @@ static_assert_eq(bswap(bswap(128lu)), 128, "bswap128 (lu) failed (3)");
#define FATAL(msg, ...) (TRACEx("FATAL", msg, ## __VA_ARGS__), abort())
// Debug testing
#define TEST_OK 1
#define TEST_FAILED 0
#define TESTFUN(name) _test__ ## name
#define CALLTEST(name) (assert_msg(TESTFUN(name)() == TEST_OK, "Test `" #name "` failed"), TRACE("Test `" #name "` passed!"))
#define DEFTEST(name) int _test__ ## name(void)
#define TEST_ASSERT(x) do { if (!(x)) {ERROR("Test `%s' assertion failure: `" #x "`", __func__ + 7); return TEST_FAILED;} } while(0)
#define TEST_ASSERT_EQ(x,y) TEST_ASSERT( (x) == (y) )
#define TEST_ASSERT_NE(x,y) TEST_ASSERT( (x) != (y) )
// Version macros
#define _AS_u32(x) ((uint32_t)(x))

@ -0,0 +1,22 @@
#ifndef _TESTH_H
#define _TESTS_H
#include <stdio.h>
#include "macros.h"
/// Run a test before `main()`
#define RUNTEST(name) __attribute__((constructor)) void _runtest__ ## name () { \
fprintf(stderr, "[!] <--- running test " #name " --- \n"); \
CALLTEST(name); \
fprintf(stderr, "[!] --- " #name " ok --->\n"); \
}
#ifdef DEBUG
#define RUNTEST_DEBUG(name) RUNTEST(name)
#else
#define RUNTEST_DEBUG(name)
#endif
DEFTEST(version_str);
#endif /* _TESTS_H */

@ -43,16 +43,13 @@ _mixin uint32_t v_ctoraw(version_t ver)
/// Print a version to a string buffer `out`. Return the number of bytes written.
///
/// Has the same semantics as `snprintf`; to calculate the length of the string needed to allocate, invoke like: `size_t sz = v_ctosn(vers, 0, NULL)`. The buffer should be allocated as `sz + 1`, and then the next call to `v_ctosn` should be like: `v_ctosn(vers, sz+1, buffer);
//XXX: Specifying `str[static ...` tells the compiler this function expects a non-null pointer. When in reality, a `NULL` pointer is used here as a sentinel value to not print... The mixin below is a hack around this, but this might introduce invalid optimisations. We should either: split the size getting function into its own thing (`v_ctosn_sz` would become a real function) that does the exact same thing as `v_ctosn(_,0,NULL)`, and not pass `NULL` to str here ever. OR, change str to regular `char *pOUT str`. The latter would be easier, but we might potentially lose out on some obscure non-NULL snprintf optimisation? For now, just use the `v_ctosn_sz` hack below. If we go with the latter, we can #define it to be just `v_ctosn(v, 0, NULL)`, otherwise move it to version.c and implement it with `snprintf(NULL, 0, ...)`.
/// Has the same semantics as `snprintf`, however, the compiler assumes `str` to be non-NULL. To get the buffer size required, use `v_ctosn_sz()` instead.
usize v_ctosn(version_t ver, usize max, char str[static pOUT max]);
_mixin usize v_ctosn_sz(version_t ver)
{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnonnull"
return v_ctosn(ver, 0, NULL);
#pragma GCC diagnostic pop
}
/// Get the buffer size required for `v_ctosn().`
///
/// Same as calling `v_ctosn(ver, 0, NULL)` but won't warn about non-NULL parameter `str`.
usize v_ctosn_sz(version_t ver);
/// Print a version to a static string buffer. The string buffer is thread local. The next call to this function on the same thread will overwrite the returned buffer.
const char* v_ctoss(version_t ver);

@ -8,27 +8,20 @@
#include <macros.h>
#include <version.h>
#include <tests.h>
int main(int argc, char** argv)
{
IGNORE(argc);
IGNORE(argv);
const u32 vraw = VERSION(100,200,101,255);
version_t vers = v_rawtoc(vraw);
INFO("main start");
usize sz = v_ctosn_sz(vers);
char verstr[sz+1];
v_ctosn(vers, sz+1, verstr);
char* verstr_h;
INFO("Version: 0x%x, raw: 0x%x", vers.raw, vraw);
INFO("Output is: (%lu chars)\t%s", sz, verstr);
INFO("Output is (static):\t%s", v_ctoss(vers));
INFO("Output is (leak):\t\t%s", (verstr_h = v_ctos(vers)));
free(verstr_h);
//INFO("Hello world %lu %lu %lu!", i, bswap(i), bswap(bswap(i)));
//INFO("Version: 0x%x (0x%x)", vers, bswap(vers)); // Check which version endian was preferrable, we'll stick with the default system endian (little, for this one.)
INFO("main end");
return 0;
}

@ -0,0 +1,36 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <ints.h>
#include <macros.h>
#include <version.h>
#include <tests.h>
DEFTEST(version_str)
{
const u32 vraw = VERSION(100,200,101,255);
version_t vers = v_rawtoc(vraw);
usize sz = v_ctosn_sz(vers);
TEST_ASSERT(sz > 0);
char verstr[sz+1];
TEST_ASSERT_EQ(v_ctosn(vers, sz+1, verstr), sz);
char* verstr_h;
INFO("Version: 0x%x, raw: 0x%x", vers.raw, vraw);
INFO("Output is: (%lu chars)\t%s", sz, verstr);
INFO("Output is (static):\t%s", v_ctoss(vers));
INFO("Output is (leak):\t\t%s", (verstr_h = v_ctos(vers)));
TEST_ASSERT(verstr_h);
free(verstr_h);
return TEST_OK;
}
RUNTEST_DEBUG(version_str)

@ -4,11 +4,22 @@
#include <version.h>
usize v_ctosn(version_t ver, usize max, char out[static pOUT max])
#define VS_FMT(comp) (comp).revision ? "%hhu.%hhu.%hhur%hhu" : "%hhu.%hhu.%hhu"
usize v_ctosn_sz(version_t ver)
{
struct v_comp comp = ver.comp;
const char* const fmt = comp.revision ? "%hhu.%hhu.%hhur%hhu" : "%hhu.%hhu.%hhu";
return snprintf(NULL, 0, VS_FMT(comp),
comp.major,
comp.minor,
comp.bugfix,
comp.revision);
}
usize v_ctosn(version_t ver, usize max, char out[static pOUT max])
{
struct v_comp comp = ver.comp;
const char* const fmt = VS_FMT(comp);
return snprintf(out, max, fmt,
comp.major,

Loading…
Cancel
Save