From 01fbb18c2755c68a778a831745ffcf0b37fca855 Mon Sep 17 00:00:00 2001 From: overflowerror Date: Fri, 17 Apr 2020 23:25:33 +0200 Subject: [PATCH] working version --- Makefile | 40 +++++++++++ src/viscocity.c | 173 ++++++++++++++++++++++++++++++++++++++++++++++++ src/viscocity.h | 35 ++++++++++ 3 files changed, 248 insertions(+) create mode 100644 Makefile create mode 100644 src/viscocity.c create mode 100644 src/viscocity.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..844f67f --- /dev/null +++ b/Makefile @@ -0,0 +1,40 @@ +CC = gcc +CFLAGS = -std=c99 -Wall -D_POSIX_C_SOURCE=201112L -D_XOPEN_SOURCE=500 -D_GNU_SOURCE -static +LD = gcc +LDFLAGS = +AR = ar +ARFLAGS = rcs + +OBJS = obj/viscocity.o +OBJS_SHARED = obj/viscocity-shared.o +DEPS = $(OBJS:%.o=%.d) + +all: libviscocity.so libviscocity.a viscocity.h + +libviscocity.so: $(OBJS_SHARED) + $(LD) $(LDFLAGS) -shared -o $@ $^ + +libviscocity.a: $(OBJS) + $(AR) $(ARFLAGS) $@ $^ + +viscocity.h: src/viscocity.h + cp $< $@ + +-include $(DEPS) + +obj/%.o: src/%.c obj + $(CC) $(CFLAGS) -MMD -c -o $@ $< + +obj/%-shared.o: src/%.c obj + $(CC) $(CFLAGS) -fPIC -MMD -c -o $@ $< + +obj: + @mkdir -p obj + +clean: + @echo "Cleaning up..." + @rm -f obj/*.o + @rm -f obj/*.d + @rm -f libviscocity.so + @rm -f libviscocity.a + @rm -f viscocity.h diff --git a/src/viscocity.c b/src/viscocity.c new file mode 100644 index 0000000..c1fe06b --- /dev/null +++ b/src/viscocity.c @@ -0,0 +1,173 @@ +#include "viscocity.h" + +#include +#include + +int failedTests = 0; +bool testOkay = true; + +const char* currentTestName; +const char* currentTestFunction; + +int totalTests = 0; + + +void _assert(bool b, const char* condition, const char* name, const char* file, int line, const char* function) { + if (!b) { + printf("\033[31mAssertion failed"); + if (name != NULL) { + + printf(": %s", name); + } + printf("\033[0m\n"); + if (condition != NULL) { + printf("%s\n", condition); + } + if (strcmp(function, "__fn__") == 0) + function = "lambda"; + + printf("in %s:%d (%s)\n", file, line, function); + + testOkay = false; + } +} + +#define MAX_CALL_ASSERTIONS (10) + +struct callAssertion { + const char* name; + int target; + int current; + enum callAssertionBehaviour behaviour; + const char* file; + int line; + const char* function; +} callAssertions[MAX_CALL_ASSERTIONS]; +int numberOfCallAssertions; + +void _assertCall(int number, const char* name, enum callAssertionBehaviour behaviour, const char* file, int line, const char* function) { + int i; + for (i = 0; i < numberOfCallAssertions; i++) { + if (strcmp(callAssertions[i].name, name) == 0) + break; + } + if (i == numberOfCallAssertions) { + numberOfCallAssertions++; + callAssertions[i] = (struct callAssertion) { + .name = name, + .target = number, + .current = 0, + .behaviour = behaviour + }; + } + + callAssertions[i].current++; + callAssertions[i].file = file; + callAssertions[i].line = line; + callAssertions[i].function = function; + +} + +#define CALL_ASSERTION_CONDITION_BUFFER_SIZE (255) + +void checkCallAssertions() { + for (int i = 0; i < numberOfCallAssertions; i++) { + struct callAssertion assertion = callAssertions[i]; + + char buffer[CALL_ASSERTION_CONDITION_BUFFER_SIZE]; + + switch(assertion.behaviour) { + case MIN: + snprintf(buffer, CALL_ASSERTION_CONDITION_BUFFER_SIZE, ">%d calls expected; got %d", assertion.target, assertion.current); + _assert(assertion.current >= assertion.target, buffer, assertion.name, assertion.file, assertion.line, assertion.function); + break; + case MAX: + snprintf(buffer, CALL_ASSERTION_CONDITION_BUFFER_SIZE, "<%d calls expected; got %d", assertion.target, assertion.current); + _assert(assertion.current <= assertion.target, buffer, assertion.name, assertion.file, assertion.line, assertion.function); + break; + case EXACT: + snprintf(buffer, CALL_ASSERTION_CONDITION_BUFFER_SIZE, "%d calls expected; got %d", assertion.target, assertion.current); + _assert(assertion.current == assertion.target, buffer, assertion.name, assertion.file, assertion.line, assertion.function); + break; + } + } +} + +void testBegin(const char* name, const char* file, int line, const char* function) { + testOkay = true; + + printf("=====================\n"); + printf("\033[33mTest %d", ++totalTests); + if (name != NULL) { + printf(": %s", name); + } + printf("\033[0m\n"); + printf("in %s:%d (%s)\n\n", file, line, function); + + currentTestName = name; + currentTestFunction = function; + numberOfCallAssertions = 0; +} + +void testEnd() { + checkCallAssertions(); + + if (!testOkay) { + failedTests++; + + printf("\n"); + printf("\033[31mTest failed\033[0m "); + /*if (currentTestName != NULL) { + printf("%s ", currentTestName); + }*/ + printf("(%s)\n\n", currentTestFunction); + } else { + printf("\033[32mTest succeeded\033[0m\n\n"); + } +} + +int testsFinal() { + printf("\n"); + if (failedTests == 0) { + printf("\033[32mAll tests were successful.\033[0m\n"); + } else { + printf("\033[31mSome tests failed.\033[0m\n"); + } + printf("%d of %d tests failed.\n", failedTests, totalTests); + + return failedTests == 0 ? 0 : 1; +} + +#define MAX_NUMBER_OF_TESTS (1<<15) + +struct test { + void (*testfunc)(); + const char* name; + const char* file; + const char* function; + int line; +} testRegister[MAX_NUMBER_OF_TESTS]; +int numberOfTests = 0; + +void addTest(void (*testfunc)(), const char* name, const char* file, const char* function, int line) { + testRegister[numberOfTests++] = (struct test) { + .testfunc = testfunc, + .name = name, + .file = file, + .function = function, + line = line + }; +} + +int doTests() { + for (int i = 0; i < numberOfTests; i++) { + struct test test = testRegister[i]; + + testBegin(test.name, test.file, test.line, test.function); + test.testfunc(); + testEnd(); + } + + return testsFinal(); +} + diff --git a/src/viscocity.h b/src/viscocity.h new file mode 100644 index 0000000..d8ff6d9 --- /dev/null +++ b/src/viscocity.h @@ -0,0 +1,35 @@ +#ifndef VISCOCITY_H +#define VISCOCITY_H + +#include +#include + +void _assert(bool, const char*, const char*, const char*, int, const char*); + +#define assertTrue(b, n) _assert(b, #b, n, __FILE__, __LINE__, __FUNCTION__) +#define assertFalse(b, n) assertTrue(!b, n) +#define assertNull(o, n) assertTrue(o == NULL, n) +#define assertNotNull(o, n) assertTrue(o != NULL, n) +#define assertStringEqual(s1, s2, n) assertTrue(strcmp(s1, s2) == 0, n) + +enum callAssertionBehaviour { + MAX, MIN, EXACT +}; + +void _assertCall(int, const char*, enum callAssertionBehaviour, const char*, int, const char*); + +#define assertCall(i, n, b) _assertCall(i, n, b, __FILE__, __LINE__, __FUNCTION__) +#define assertCallMin(i, n) assertCall(i, n, MIN) +#define assertCallMax(i, n) assertCall(i, n, MAX) +#define assertCallExact(i, n) assertCall(i, n, EXACT) + + +void addTest(void (*)(), const char*, const char*, const char*, int); + +#define test(f, n) void test_##f(); \ +__attribute__((constructor)) void register##f() { addTest(& test_##f, n, __FILE__, "test_" # f, __LINE__); }\ +void test_##f() + +int doTests(); + +#endif