2024-07-12 22:29:04 +08:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <cstdio>
|
|
|
|
#include <cstdlib>
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
void print_value(const T& value);
|
|
|
|
|
|
|
|
template <>
|
|
|
|
void print_value(const int8_t& value) {
|
|
|
|
printf("%d", value);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
void print_value(const int32_t& value) {
|
|
|
|
printf("%d", value);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
void print_value(const uint8_t& value) {
|
|
|
|
printf("%u", value);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
void print_value(const uint32_t& value) {
|
|
|
|
printf("%u", value);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
void print_value(const float& value) {
|
|
|
|
printf("%f", value);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
void print_value(const double& value) {
|
|
|
|
printf("%f", value);
|
|
|
|
}
|
|
|
|
|
|
|
|
void __begin_test(const char* function_name, const char* file, int line) {
|
|
|
|
printf("######### Running %s @ %s:%d\n", function_name, file, line);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define BEGIN_TEST() __begin_test(__FUNCTION__, __FILE__, __LINE__)
|
|
|
|
|
|
|
|
void test_fail() {
|
|
|
|
printf("[!] Test failed. Exiting with status code 1.\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void debug_print_array(int len, const T* as) {
|
|
|
|
printf("[");
|
|
|
|
for (int i = 0; i < len; i++) {
|
|
|
|
if (i != 0) printf(", ");
|
|
|
|
print_value(as[i]);
|
|
|
|
}
|
|
|
|
printf("]");
|
|
|
|
}
|
|
|
|
|
|
|
|
void print_assertion_passed(const char* file, int line) {
|
|
|
|
printf("[*] Assertion passed on %s:%d\n", file, line);
|
|
|
|
}
|
|
|
|
|
|
|
|
void print_assertion_failed(const char* file, int line) {
|
|
|
|
printf("[!] Assertion failed on %s:%d\n", file, line);
|
|
|
|
}
|
|
|
|
|
|
|
|
void __assert_true(const char* file, int line, bool cond) {
|
|
|
|
if (cond) {
|
|
|
|
print_assertion_passed(file, line);
|
|
|
|
} else {
|
|
|
|
print_assertion_failed(file, line);
|
|
|
|
test_fail();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#define assert_true(cond) __assert_true(__FILE__, __LINE__, cond)
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void __assert_arrays_match(const char* file, int line, int len,
|
|
|
|
const T* expected, const T* got) {
|
|
|
|
if (arrays_match(len, expected, got)) {
|
|
|
|
print_assertion_passed(file, line);
|
|
|
|
} else {
|
|
|
|
print_assertion_failed(file, line);
|
|
|
|
printf("Expect = ");
|
|
|
|
debug_print_array(len, expected);
|
|
|
|
printf("\n");
|
|
|
|
printf(" Got = ");
|
|
|
|
debug_print_array(len, got);
|
|
|
|
printf("\n");
|
|
|
|
test_fail();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#define assert_arrays_match(len, expected, got) \
|
|
|
|
__assert_arrays_match(__FILE__, __LINE__, len, expected, got)
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void __assert_values_match(const char* file, int line, T expected, T got) {
|
|
|
|
if (expected == got) {
|
|
|
|
print_assertion_passed(file, line);
|
|
|
|
} else {
|
|
|
|
print_assertion_failed(file, line);
|
|
|
|
printf("Expect = ");
|
|
|
|
print_value(expected);
|
|
|
|
printf("\n");
|
|
|
|
printf(" Got = ");
|
|
|
|
print_value(got);
|
|
|
|
printf("\n");
|
|
|
|
test_fail();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#define assert_values_match(expected, got) \
|
2024-07-26 14:06:18 +08:00
|
|
|
__assert_values_match(__FILE__, __LINE__, expected, got)
|
|
|
|
|
|
|
|
// A fake set of ExceptionIds for testing only
|
|
|
|
const ErrorContextExceptions TEST_ERROR_CONTEXT_EXCEPTIONS = {
|
|
|
|
.index_error = 0,
|
|
|
|
.value_error = 1,
|
|
|
|
.assertion_error = 2,
|
|
|
|
.runtime_error = 3,
|
|
|
|
.type_error = 4,
|
|
|
|
};
|
|
|
|
|
|
|
|
ErrorContext create_testing_errctx() {
|
|
|
|
// Everything is global so it is fine to directly return a struct
|
|
|
|
// ErrorContext
|
|
|
|
ErrorContext errctx;
|
|
|
|
errctx.initialize(&TEST_ERROR_CONTEXT_EXCEPTIONS);
|
|
|
|
return errctx;
|
|
|
|
}
|
|
|
|
|
|
|
|
void print_errctx_content(ErrorContext* errctx) {
|
|
|
|
if (errctx->has_exception()) {
|
|
|
|
printf(
|
|
|
|
"(Exception ID %d): %s ... where param1 = %ld, param2 = %ld, "
|
|
|
|
"param3 = "
|
|
|
|
"%ld\n",
|
|
|
|
errctx->exception_id, errctx->msg, errctx->param1, errctx->param2,
|
|
|
|
errctx->param3);
|
|
|
|
} else {
|
|
|
|
printf("<no exception>\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void __assert_errctx_no_exception(const char* file, int line,
|
|
|
|
ErrorContext* errctx) {
|
|
|
|
if (errctx->has_exception()) {
|
|
|
|
print_assertion_failed(file, line);
|
|
|
|
printf("Expecting no exception but caught the following:\n\n");
|
|
|
|
print_errctx_content(errctx);
|
|
|
|
test_fail();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#define assert_errctx_no_exception(errctx) \
|
|
|
|
__assert_errctx_no_exception(__FILE__, __LINE__, errctx)
|
|
|
|
|
|
|
|
void __assert_errctx_has_exception(const char* file, int line,
|
|
|
|
ErrorContext* errctx,
|
|
|
|
ExceptionId expected_exception_id) {
|
|
|
|
if (errctx->has_exception()) {
|
|
|
|
if (errctx->exception_id != expected_exception_id) {
|
|
|
|
print_assertion_failed(file, line);
|
|
|
|
printf(
|
|
|
|
"Expecting exception id %d but got exception id %d. Error "
|
|
|
|
"caught:\n\n",
|
|
|
|
expected_exception_id, errctx->exception_id);
|
|
|
|
print_errctx_content(errctx);
|
|
|
|
test_fail();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
print_assertion_failed(file, line);
|
|
|
|
printf("Expecting an exception, but there is none.");
|
|
|
|
test_fail();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#define assert_errctx_has_exception(errctx, expected_exception_id) \
|
|
|
|
__assert_errctx_has_exception(__FILE__, __LINE__, errctx, \
|
|
|
|
expected_exception_id)
|