#include <tests/ktest_internal.h>
#include <kern/misc_protos.h>
#include <kern/debug.h>
#define EMIT(buf, size) do {\
console_write(buf, size); \
} while(0)
#define BOUNDS_CHECK_AND_UPDATE(ret, size) do {\
if(ret < 0 || ret >= size) {\
panic("Internal ktest error in %s", __func__);\
}\
size -= ret;\
msg += ret;\
} while(0)
int vsnprintf(char *, size_t, const char *, va_list);
void
ktest_emit_start(void)
{
char str[] = "\n[KTEST]\tSTART\t" KTEST_VERSION_STR "\n";
EMIT((char *)&str[0], sizeof(str) - 1);
}
void
ktest_emit_finish(void)
{
char str[] = "\n[KTEST]\tFINISH\n";
EMIT((char *)&str[0], sizeof(str) - 1);
}
void
ktest_emit_testbegin(const char * test_name)
{
char * msg = ktest_output_buf;
int size = sizeof(ktest_output_buf);
int ret;
const char *fname = strnstr((char *)(uintptr_t)ktest_current_file, "xnu", 100);
ret = snprintf(msg,
size,
"\n[KTEST]\t"
"TESTBEGIN\t"
"%lld\t"
"%d\t"
"%s\t"
"%d\t"
"%s\n",
ktest_current_time,
ktest_test_index,
fname,
ktest_current_line,
test_name);
BOUNDS_CHECK_AND_UPDATE(ret, size);
EMIT(ktest_output_buf, (int)(msg - ktest_output_buf));
}
void
ktest_emit_testskip(const char * skip_msg, va_list args)
{
char * msg = ktest_output_buf;
int size = sizeof(ktest_output_buf);
int ret;
const char *fname = strnstr((char *)(uintptr_t)ktest_current_file, "xnu", 100);
ret = snprintf(msg,
size,
"\n[KTEST]\t"
"TESTSKIP\t"
"%lld\t"
"%s\t"
"%d\t",
ktest_current_time,
fname,
ktest_current_line);
BOUNDS_CHECK_AND_UPDATE(ret, size);
ret = vsnprintf(msg, size, skip_msg, args);
BOUNDS_CHECK_AND_UPDATE(ret, size);
ret = snprintf(msg, size, "\n");
BOUNDS_CHECK_AND_UPDATE(ret, size);
EMIT(ktest_output_buf, (int)(msg - ktest_output_buf));
}
void
ktest_emit_testend()
{
char * msg = ktest_output_buf;
int size = sizeof(ktest_output_buf);
int ret;
const char *fname = strnstr((char *)(uintptr_t)ktest_current_file, "xnu", 100);
ret = snprintf(msg,
size,
"\n[KTEST]\t"
"TESTEND\t"
"%lld\t"
"%d\t"
"%s\t"
"%d\t"
"%s\n",
ktest_current_time,
ktest_test_index,
fname,
ktest_current_line,
ktest_test_name);
BOUNDS_CHECK_AND_UPDATE(ret, size);
EMIT(ktest_output_buf, (int)(msg - ktest_output_buf));
}
void
ktest_emit_log(const char * log_msg, va_list args)
{
char * msg = ktest_output_buf;
int size = sizeof(ktest_output_buf);
int ret;
const char *fname = strnstr((char *)(uintptr_t)ktest_current_file, "xnu", 100);
ret = snprintf(msg,
size,
"\n[KTEST]\t"
"LOG\t"
"%lld\t"
"%s\t"
"%d\t",
ktest_current_time,
fname,
ktest_current_line);
BOUNDS_CHECK_AND_UPDATE(ret, size);
ret = vsnprintf(msg, size, log_msg, args);
BOUNDS_CHECK_AND_UPDATE(ret, size);
ret = snprintf(msg, size, "\n");
BOUNDS_CHECK_AND_UPDATE(ret, size);
EMIT(ktest_output_buf, (int)(msg - ktest_output_buf));
}
void
ktest_emit_perfdata(const char * metric, const char * unit, double value, const char * desc)
{
static const char * perfstr = "%s\t%lld\t%s\t\"%s\"";
char * msg = ktest_output_buf;
int64_t print_value = (int64_t)value;
int size = sizeof(ktest_output_buf);
int ret;
const char *fname = strnstr((char *)(uintptr_t)ktest_current_file, "xnu", 100);
ret = snprintf(msg, size,
"\n[KTEST]\t"
"PERF\t"
"%lld\t"
"%s\t"
"%d\t",
ktest_current_time,
fname,
ktest_current_line);
BOUNDS_CHECK_AND_UPDATE(ret, size);
ret = snprintf(msg, size, perfstr, metric, print_value, unit, desc);
BOUNDS_CHECK_AND_UPDATE(ret, size);
ret = snprintf(msg, size, "\n");
BOUNDS_CHECK_AND_UPDATE(ret, size);
EMIT(ktest_output_buf, (int)(msg - ktest_output_buf));
}
void
ktest_emit_testcase(void)
{
char * msg = ktest_output_buf;
int size = sizeof(ktest_output_buf);
int ret;
const char *fname = strnstr((char *)(uintptr_t)ktest_current_file, "xnu", 100);
ret = snprintf(msg,
size,
"\n[KTEST]\t"
"%s\t"
"%lld\t"
"%d\t"
"%s\t"
"%d\t"
"%s\t"
"%s",
ktest_testcase_result_tokens[ktest_testcase_mode]
[ktest_testcase_result],
ktest_current_time,
ktest_expression_index,
fname,
ktest_current_line,
ktest_current_msg,
ktest_current_expr);
BOUNDS_CHECK_AND_UPDATE(ret, size);
for (int i = 0; ktest_current_var_names[i][0]; i++) {
ret = snprintf(msg,
size,
"\t%s\t%s",
ktest_current_var_names[i],
ktest_current_var_values[i]);
BOUNDS_CHECK_AND_UPDATE(ret, size);
}
ret = snprintf(msg, size, "\n");
BOUNDS_CHECK_AND_UPDATE(ret, size);
EMIT(ktest_output_buf, (int)(msg - ktest_output_buf));
}