150 lines
4.4 KiB
C
150 lines
4.4 KiB
C
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <math.h>
|
|
#include <libgen.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include "cputime.h"
|
|
#include "buffer.h"
|
|
|
|
typedef enum {
|
|
TestStatusSkipped = 0,
|
|
TestStatusFailure,
|
|
TestStatusOk,
|
|
TestStatusFailureHexdump
|
|
} TestStatus;
|
|
|
|
typedef struct {
|
|
TestStatus status;
|
|
char *message;
|
|
Buffer *buffer;
|
|
Buffer *template;
|
|
} TestResult;
|
|
|
|
typedef TestResult (*TestPointer)(void);
|
|
|
|
typedef struct {
|
|
char *name;
|
|
TestPointer run;
|
|
char *file;
|
|
int line;
|
|
} DefinedTest;
|
|
|
|
extern DefinedTest defined_tests[];
|
|
|
|
#define TEST(_name, _function) (DefinedTest){ _name, _function, __FILE__, __LINE__ }
|
|
|
|
#define TESTS(...) \
|
|
DefinedTest defined_tests[] = { \
|
|
__VA_ARGS__, \
|
|
TEST(NULL, NULL) \
|
|
}
|
|
|
|
#define TEST_OK() return (TestResult){ TestStatusOk, NULL, NULL, NULL }
|
|
#define TESTRESULT(_status, _message) return (TestResult){ _status, _message, NULL, NULL }
|
|
#define TESTRESULT_BUFFER(_status, _message, _buffer, _template) return (TestResult){ _status, _message, _buffer, _template }
|
|
|
|
#ifdef TIMETRIAL
|
|
# define TESTASSERT(_assertion, _message) if (!(_assertion)) { return (TestResult){ TestStatusFailure, NULL, NULL, NULL }; }
|
|
#else
|
|
# define TESTASSERT(_assertion, _message) if (!(_assertion)) { return (TestResult){ TestStatusFailure, _message, NULL, NULL }; }
|
|
#endif
|
|
|
|
|
|
static inline TestResult TESTMEMCMP(Buffer *template, Buffer *check) {
|
|
if (template->len != check->len) {
|
|
TESTRESULT_BUFFER(TestStatusFailureHexdump, "Buffer size differs from template", check, template);
|
|
}
|
|
if (memcmp(template->data, check->data, template->len) == 0) {
|
|
TESTRESULT(TestStatusOk, "Buffer matches template");
|
|
} else {
|
|
TESTRESULT_BUFFER(TestStatusFailureHexdump, "Buffer and template differ", check, template);
|
|
}
|
|
}
|
|
|
|
// not implemented placeholder
|
|
|
|
static TestResult not_implemented(void) {
|
|
TESTRESULT(TestStatusSkipped, "Not implemented");
|
|
}
|
|
|
|
|
|
void timetrial(DefinedTest *test);
|
|
|
|
int main(int argc, char **argv) {
|
|
uint16_t successes = 0;
|
|
uint16_t skips = 0;
|
|
uint16_t failures = 0;
|
|
|
|
for(DefinedTest *test = defined_tests; test->run != NULL; test++) {
|
|
TestResult result = test->run();
|
|
switch (result.status) {
|
|
case TestStatusOk:
|
|
successes++;
|
|
fprintf(stdout, "info: Test %s suceeded ", test->name);
|
|
#ifdef TIMETRIAL
|
|
timetrial(test);
|
|
#else
|
|
fprintf(stdout, "\n");
|
|
#endif
|
|
break;
|
|
case TestStatusSkipped:
|
|
skips++;
|
|
fprintf(stderr, "%s:%d: warning: Skipped test %s\n", test->file, test->line, test->name);
|
|
if (result.message) {
|
|
fprintf(stderr, " -> %s\n", result.message);
|
|
}
|
|
break;
|
|
case TestStatusFailure:
|
|
failures++;
|
|
fprintf(stderr, "%s:%d: error: Test %s failed\n", test->file, test->line, test->name);
|
|
if (result.message) {
|
|
fprintf(stderr, " -> %s\n", result.message);
|
|
}
|
|
break;
|
|
case TestStatusFailureHexdump:
|
|
failures++;
|
|
fprintf(stderr, "%s:%d: error: Test %s failed\n", test->file, test->line, test->name);
|
|
if (result.message) {
|
|
fprintf(stderr, " -> %s\n", result.message);
|
|
}
|
|
if (result.template) {
|
|
fprintf(stderr, " -> Template (%zu bytes)\n", result.template->len);
|
|
buffer_hexdump(result.template, 5);
|
|
}
|
|
if (result.buffer) {
|
|
fprintf(stderr, " -> Buffer (%zu bytes)\n", result.buffer->len);
|
|
buffer_hexdump(result.buffer, 5);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
fprintf(stderr, "\n%d Tests, %d skipped, %d succeeded, %d failed\n\n",
|
|
skips + successes + failures,
|
|
skips,
|
|
successes,
|
|
failures
|
|
);
|
|
|
|
return failures > 0;
|
|
}
|
|
|
|
#ifdef TIMETRIAL
|
|
#define ITER 10000000
|
|
void timetrial(DefinedTest *test) {
|
|
double start, end;
|
|
|
|
start = getCPUTime();
|
|
for(uint64_t i = 0; i < ITER; i++) {
|
|
volatile TestResult result = test->run();
|
|
(void)result;
|
|
}
|
|
end = getCPUTime();
|
|
|
|
double time = (end - start) * 1000.0 /* ms */ * 1000.0 /* us */ * 1000.0 /* ns */ / (double)ITER;
|
|
fprintf(stdout, "[ %0.3f ns ]\n", time);
|
|
}
|
|
#endif
|