Files
zinnia/tests/user/lib/utest.c
T
2026-10-27 23:11:15 +01:00

211 lines
5.2 KiB
C

// SPDX-License-Identifier: ISC
#include "utest.h"
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "syscall.h"
constexpr size_t LINE_MAX = 240;
extern const struct utest_case __start_utest_cases[];
extern const struct utest_case __stop_utest_cases[];
size_t strlen(const char* str) {
size_t len = 0;
while (str[len])
len++;
return len;
}
int memcmp(const void* s1, const void* s2, size_t size) {
const uint8_t* a = s1;
const uint8_t* b = s2;
for (size_t i = 0; i < size; i++) {
if (a[i] != b[i])
return a[i] < b[i] ? -1 : 1;
}
return 0;
}
void* memcpy(void* restrict dest, const void* restrict src, size_t n) {
uint8_t* d = dest;
const uint8_t* s = src;
for (size_t i = 0; i < n; i++)
d[i] = s[i];
return dest;
}
void* memset(void* dest, int value, size_t n) {
uint8_t* d = dest;
for (size_t i = 0; i < n; i++)
d[i] = (uint8_t)value;
return dest;
}
bool utest_streq(const char* a, const char* b) {
if (!a || !b)
return a == b;
while (*a && *a == *b) {
a++;
b++;
}
return *a == *b;
}
struct line {
char buf[LINE_MAX];
size_t len;
};
static void put(struct line* line, char c) {
if (line->len < sizeof(line->buf) - 1)
line->buf[line->len++] = c;
}
static void put_str(struct line* line, const char* str) {
for (; *str; str++)
put(line, *str);
}
static void put_num(struct line* line, unsigned long long value, unsigned base, bool negative, bool prefix) {
char digits[24];
size_t n = 0;
do {
digits[n++] = "0123456789abcdef"[value % base];
value /= base;
} while (value);
if (negative)
put(line, '-');
if (prefix)
put_str(line, "0x");
while (n)
put(line, digits[--n]);
}
static void format(struct line* line, const char* fmt, va_list args) {
for (; *fmt; fmt++) {
if (*fmt != '%') {
put(line, *fmt);
continue;
}
fmt++;
bool alt = false;
if (*fmt == '#') {
alt = true;
fmt++;
}
int longs = 0;
bool size = false;
for (;; fmt++) {
if (*fmt == 'l')
longs++;
else if (*fmt == 'z')
size = true;
else
break;
}
switch (*fmt) {
case 'd':
case 'i': {
long long v = size ? (long long)va_arg(args, ptrdiff_t)
: longs ? va_arg(args, long long)
: va_arg(args, int);
put_num(line, v < 0 ? -(unsigned long long)v : (unsigned long long)v, 10, v < 0, false);
break;
}
case 'u':
case 'x': {
unsigned long long v = size ? va_arg(args, size_t)
: longs ? va_arg(args, unsigned long long)
: va_arg(args, unsigned int);
put_num(line, v, *fmt == 'x' ? 16 : 10, false, alt && *fmt == 'x');
break;
}
case 'p':
put_num(line, (uintptr_t)va_arg(args, void*), 16, false, true);
break;
case 's': {
const char* s = va_arg(args, const char*);
put_str(line, s ? s : "(null)");
break;
}
case 'c':
put(line, (char)va_arg(args, int));
break;
case '%':
put(line, '%');
break;
default:
put(line, '?');
break;
}
}
}
static void emit(struct line* line) {
line->buf[line->len] = 0;
sys_syslog(SYSLOG_INFO, line->buf, line->len);
}
void utest_log(const char* fmt, ...) {
struct line line = {};
va_list args;
va_start(args, fmt);
format(&line, fmt, args);
va_end(args);
emit(&line);
}
void utest_fail(struct utest* test, const char* file, int line_nr, const char* fmt, ...) {
struct line line = {};
put_str(&line, "# ");
put_str(&line, test->suite);
put(&line, '.');
put_str(&line, test->name);
put_str(&line, ": ");
put_str(&line, file);
put(&line, ':');
put_num(&line, (unsigned)line_nr, 10, false, false);
put_str(&line, ": ");
va_list args;
va_start(args, fmt);
format(&line, fmt, args);
va_end(args);
emit(&line);
test->failed = true;
}
void utest_run_all() {
size_t index = 0;
for (const struct utest_case* c = __start_utest_cases; c < __stop_utest_cases; c++) {
struct utest test = {.suite = c->suite, .name = c->name};
c->func(&test);
index++;
if (test.skipped)
utest_log("ok %zu %s.%s # SKIP %s", index, c->suite, c->name, test.skip_reason ? test.skip_reason : "");
else if (c->xfail_reason)
utest_log(
"%s %zu %s.%s # TODO %s",
test.failed ? "not ok" : "ok",
index,
c->suite,
c->name,
c->xfail_reason
);
else
utest_log("%s %zu %s.%s", test.failed ? "not ok" : "ok", index, c->suite, c->name);
}
utest_log("1..%zu", index);
}
int main() {
utest_run_all();
for (;;)
;
}