improved tests (no registertest, skipping tests, catching exceptions)

This commit is contained in:
mrbesen 2022-04-10 14:33:30 +02:00
parent a72c4fbac1
commit 226131d504
Signed by: MrBesen
GPG Key ID: 596B2350DCD67504
4 changed files with 74 additions and 35 deletions

View File

@ -7,25 +7,36 @@
#define RED "\033[1;91m" #define RED "\033[1;91m"
#define GREEN "\033[1;92m" #define GREEN "\033[1;92m"
#define YELLOW "\033[1;93m"
#define AQUA "\033[1;36m" #define AQUA "\033[1;36m"
#define RESET "\033[;1m" #define RESET "\033[;1m"
extern std::map<std::string, test_t> tests;
void loadTests();
int main(int argc, char** argv) { int main(int argc, char** argv) {
auto start = std::chrono::high_resolution_clock::now(); auto start = std::chrono::high_resolution_clock::now();
loadTests(); testdef* startit = &__start_testlist, *endit = &__stop_testlist;
int failcount = 0; int failcount = 0;
int testcount = tests.size(); int skipcount = 0;
int testcount = endit-startit;
int testnumber = 0; int testnumber = 0;
for(std::map<std::string, test_t>::iterator current = tests.begin(); current != tests.end(); ++current) {
printf("\033[1mRunning test: %d/%d " AQUA "%s " RESET, ++testnumber, testcount, current->first.c_str()); // go through back -> front (tests are inserted in reverse order)
if((current->second)()) { for(testdef* it = startit + testcount-1; it >= startit; --it) {
printf("\033[1mRunning test: %d/%d " AQUA "%s " RESET, ++testnumber, testcount, it->name);
// run test
int result = TESTFAILED;
try {
result = (it->testf)();
} catch(std::exception& e) {
std::cout << "catched exception: \"" << e.what() << "\" " << std::flush;
} catch(...) {}
if(result == TESTGOOD) {
printf(GREEN "succeeded" RESET "!\n"); printf(GREEN "succeeded" RESET "!\n");
} else if(result == TESTSKIPPED) {
printf(YELLOW "skipped" RESET "!\n");
skipcount++;
} else { } else {
printf(RED "failed" RESET "\n"); printf(RED "failed" RESET "\n");
failcount++; failcount++;
@ -33,7 +44,7 @@ int main(int argc, char** argv) {
} }
const char* color = (failcount > 0 ? RED : GREEN); // red or green const char* color = (failcount > 0 ? RED : GREEN); // red or green
printf("%s%d" RESET "/%d failed\n", color, failcount, testcount); printf("%s%d" RESET "/%d failed (" YELLOW "%d " RESET "skipped)\n", color, failcount, testcount, skipcount);
auto end = std::chrono::high_resolution_clock::now(); auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> t = end - start; std::chrono::duration<double> t = end - start;

View File

@ -1,11 +1,29 @@
#include "test.h" #include "test.h"
#include <stdexcept>
// tests are executed top to bottom
// never fail
TEST(ABC) { TEST(ABC) {
CMPASSERT(1, true); CMPASSERT(1, true);
} TESTEND } TESTEND
// always fail
TEST(CDE) { TEST(CDE) {
CMPASSERT(0, true); CMPASSERT(0, true);
} TESTEND } TESTEND
// always skip
TEST(FGH) {
SKIPTEST;
} TESTEND
// always throw
TEST(IJK) {
throw std::runtime_error("test exception");
} TESTEND

View File

@ -1,17 +1,43 @@
#define TESTFAILED 0 #define TESTFAILED 0
#define TESTGOOD 1 #define TESTGOOD 1
#define TESTSKIPPED -1
#include <iostream> #include <iostream>
#define TESTDATA "./tests/data/" #define TESTDATA "./tests/data/"
#define TESTNAME(NAME) test_##NAME // very helpfull: https://mgalgs.io/2013/05/10/hacking-your-ELF-for-fun-and-profit.html
#define TESTFUNC(NAME) bool TESTNAME(NAME)()
#define TEST(NAME) TESTFUNC(NAME) {
#define TESTEND return TESTGOOD; }
#define ASSERT(BED, ERR) if(!(BED)) { std::cout << __FILE__ << ":" << __LINE__ << " " << ERR << std::endl; return TESTFAILED; } #define TESTNAME(NAME) test_##NAME
#define CMPASSERTE(A, B, ERR) if( !((A) == (B))) { std::cout << __FILE__ << ":" << __LINE__ << " is: \"" << (A) << "\" should: \"" << (B) << "\""<< std::endl; return TESTFAILED; } #define TESTFUNC(NAME) int TESTNAME(NAME)()
#define REGISTERTEST(NAME) static const testdef __test_ ## NAME \
__attribute((__section__("testlist"))) \
__attribute((__used__)) = { \
TESTNAME(NAME), \
#NAME, \
}
#define TEST(NAME) static TESTFUNC(NAME); \
REGISTERTEST(NAME); \
TESTFUNC(NAME) {
#define TESTEND return TESTGOOD; } \
#define ASSERT(BED, ERR) if(!(BED)) { std::cout << __FILE__ << ":" << __LINE__ << " " << ERR << ' ' << std::flush; return TESTFAILED; }
#define CMPASSERTE(A, B, ERR) if( !((A) == (B))) { std::cout << __FILE__ << ":" << __LINE__ << " is: \"" << (A) << "\" should: \"" << (B) << "\" "<< std::flush; return TESTFAILED; }
#define CMPASSERT(A, B) CMPASSERTE(A, B, "") #define CMPASSERT(A, B) CMPASSERTE(A, B, "")
typedef bool (*test_t)(); #define SKIPTEST return TESTSKIPPED
typedef int (*test_t)();
struct testdef {
test_t testf;
const char* name;
};
// linker generates this <3
extern struct testdef __start_testlist;
extern struct testdef __stop_testlist;

View File

@ -1,16 +0,0 @@
#include "test.h"
#include <map>
#include <string>
#define REGISTERTEST(NAME) tests.insert({#NAME, TESTNAME(NAME)})
TESTFUNC(ABC);
TESTFUNC(CDE);
std::map<std::string, test_t> tests;
void loadTests() {
REGISTERTEST(ABC);
REGISTERTEST(CDE);
}