#ifndef AWS_TESTING_AWS_TEST_HARNESS_H
#define AWS_TESTING_AWS_TEST_HARNESS_H
/**
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0.
 */

#include <aws/common/common.h>
#include <aws/common/error.h>
#include <aws/common/logging.h>
#include <aws/common/mutex.h>
#include <aws/common/system_info.h>

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/**
 * The return code for skipped tests. Use the return code if the test should be skipped.
 */
#define AWS_OP_SKIP (-2)

#ifndef AWS_UNSTABLE_TESTING_API
#    error The AWS Test Fixture is designed only for use by AWS owned libraries for the AWS C99 SDK. You are welcome to use it,   \
but you should be aware we make no promises on the stability of this API.  To enable use of the aws test fixtures, set \
the AWS_UNSTABLE_TESTING_API compiler flag
#endif

#ifndef AWS_TESTING_REPORT_FD
#    define AWS_TESTING_REPORT_FD stderr
#endif

#ifdef _MSC_VER
#    pragma warning(disable : 4221) /* aggregate initializer using local variable addresses */
#    pragma warning(disable : 4204) /* non-constant aggregate initializer */
#endif

#if defined(__clang__)
#    pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
#endif

/** Prints a message to AWS_TESTING_REPORT_FD using printf format that appends the function, file and line number.
 * If format is null, returns 0 without printing anything; otherwise returns 1.
 */
static int s_cunit_failure_message0(
    const char *prefix,
    const char *function,
    const char *file,
    int line,
    const char *format,
    ...) {
    if (!format) {
        return 0;
    }

    fprintf(AWS_TESTING_REPORT_FD, "%s", prefix);

    va_list ap;
    va_start(ap, format);
    vfprintf(AWS_TESTING_REPORT_FD, format, ap);
    va_end(ap);

    fprintf(AWS_TESTING_REPORT_FD, " [%s(): %s:%d]\n", function, file, line);

    return 1;
}

#define FAIL_PREFIX "***FAILURE*** "
#define CUNIT_FAILURE_MESSAGE(func, file, line, format, ...)                                                           \
    s_cunit_failure_message0(FAIL_PREFIX, func, file, line, format, #__VA_ARGS__)

static int total_failures;
static int total_skip;

#define SUCCESS (0)
#define FAILURE (-1)
/* The skip code returned to ctest to indicate the test is skipped. Refer to cmake doc:
 * https://cmake.org/cmake/help/latest/prop_test/SKIP_RETURN_CODE.html */
#define SKIP (1)

#define POSTSKIP_INTERNAL()                                                                                            \
    do {                                                                                                               \
        total_skip++;                                                                                                  \
        return SKIP;                                                                                                   \
    } while (0)

#define RETURN_SKIP(format, ...)                                                                                       \
    do {                                                                                                               \
        printf(format, ##__VA_ARGS__);                                                                                 \
        printf("\n");                                                                                                  \
        POSTSKIP_INTERNAL();                                                                                           \
    } while (0)

#define RETURN_SUCCESS(format, ...)                                                                                    \
    do {                                                                                                               \
        printf(format, ##__VA_ARGS__);                                                                                 \
        printf("\n");                                                                                                  \
        return SUCCESS;                                                                                                \
    } while (0)

#define PRINT_FAIL_INTERNAL(...) CUNIT_FAILURE_MESSAGE(__func__, __FILE__, __LINE__, ##__VA_ARGS__, (const char *)NULL)

#define PRINT_FAIL_INTERNAL0(...)                                                                                      \
    s_cunit_failure_message0(FAIL_PREFIX, __func__, __FILE__, __LINE__, ##__VA_ARGS__, (const char *)NULL)

#define POSTFAIL_INTERNAL()                                                                                            \
    do {                                                                                                               \
        total_failures++;                                                                                              \
        return FAILURE;                                                                                                \
    } while (0)

#define FAIL(...)                                                                                                      \
    do {                                                                                                               \
        PRINT_FAIL_INTERNAL0(__VA_ARGS__);                                                                             \
        POSTFAIL_INTERNAL();                                                                                           \
    } while (0)

#define ASSERT_TRUE(condition, ...)                                                                                    \
    do {                                                                                                               \
        if (!(condition)) {                                                                                            \
            if (!PRINT_FAIL_INTERNAL0(__VA_ARGS__)) {                                                                  \
                PRINT_FAIL_INTERNAL0("Expected condition to be true: " #condition);                                    \
            }                                                                                                          \
            POSTFAIL_INTERNAL();                                                                                       \
        }                                                                                                              \
    } while (0)

#define ASSERT_FALSE(condition, ...)                                                                                   \
    do {                                                                                                               \
        if ((condition)) {                                                                                             \
            if (!PRINT_FAIL_INTERNAL0(__VA_ARGS__)) {                                                                  \
                PRINT_FAIL_INTERNAL0("Expected condition to be false: " #condition);                                   \
            }                                                                                                          \
            POSTFAIL_INTERNAL();                                                                                       \
        }                                                                                                              \
    } while (0)

#define ASSERT_SUCCESS(condition, ...)                                                                                 \
    do {                                                                                                               \
        int assert_rv = (condition);                                                                                   \
        if (assert_rv != AWS_OP_SUCCESS) {                                                                             \
            if (!PRINT_FAIL_INTERNAL0(__VA_ARGS__)) {                                                                  \
                PRINT_FAIL_INTERNAL0(                                                                                  \
                    "Expected success at %s; got return value %d with last error 0x%04x\n",                            \
                    #condition,                                                                                        \
                    assert_rv,                                                                                         \
                    aws_last_error());                                                                                 \
            }                                                                                                          \
            POSTFAIL_INTERNAL();                                                                                       \
        }                                                                                                              \
    } while (0)

#define ASSERT_FAILS(condition, ...)                                                                                   \
    do {                                                                                                               \
        int assert_rv = (condition);                                                                                   \
        if (assert_rv != AWS_OP_ERR) {                                                                                 \
            if (!PRINT_FAIL_INTERNAL0(__VA_ARGS__)) {                                                                  \
                PRINT_FAIL_INTERNAL0(                                                                                  \
                    "Expected failure at %s; got return value %d with last error 0x%04x\n",                            \
                    #condition,                                                                                        \
                    assert_rv,                                                                                         \
                    aws_last_error());                                                                                 \
            }                                                                                                          \
            POSTFAIL_INTERNAL();                                                                                       \
        }                                                                                                              \
    } while (0)

#define ASSERT_ERROR(error, condition, ...)                                                                            \
    do {                                                                                                               \
        int assert_rv = (condition);                                                                                   \
        int assert_err = aws_last_error();                                                                             \
        int assert_err_expect = (error);                                                                               \
        if (assert_rv != AWS_OP_ERR) {                                                                                 \
            fprintf(                                                                                                   \
                AWS_TESTING_REPORT_FD,                                                                                 \
                "%sExpected error but no error occurred; rv=%d, aws_last_error=%04x (expected %04x): ",                \
                FAIL_PREFIX,                                                                                           \
                assert_rv,                                                                                             \
                assert_err,                                                                                            \
                assert_err_expect);                                                                                    \
            if (!PRINT_FAIL_INTERNAL0(__VA_ARGS__)) {                                                                  \
                PRINT_FAIL_INTERNAL0("%s", #condition);                                                                \
            }                                                                                                          \
            POSTFAIL_INTERNAL();                                                                                       \
        }                                                                                                              \
        if (assert_err != assert_err_expect) {                                                                         \
            fprintf(                                                                                                   \
                AWS_TESTING_REPORT_FD,                                                                                 \
                "%sIncorrect error code; aws_last_error=%04x (expected %04x): ",                                       \
                FAIL_PREFIX,                                                                                           \
                assert_err,                                                                                            \
                assert_err_expect);                                                                                    \
            if (!PRINT_FAIL_INTERNAL0(__VA_ARGS__)) {                                                                  \
                PRINT_FAIL_INTERNAL0("%s", #condition);                                                                \
            }                                                                                                          \
            POSTFAIL_INTERNAL();                                                                                       \
        }                                                                                                              \
    } while (0)

#define ASSERT_NULL(ptr, ...)                                                                                          \
    do {                                                                                                               \
        /* XXX: Some tests use ASSERT_NULL on ints... */                                                               \
        void *assert_p = (void *)(uintptr_t)(ptr);                                                                     \
        if (assert_p) {                                                                                                \
            fprintf(AWS_TESTING_REPORT_FD, "%sExpected null but got %p: ", FAIL_PREFIX, assert_p);                     \
            if (!PRINT_FAIL_INTERNAL0(__VA_ARGS__)) {                                                                  \
                PRINT_FAIL_INTERNAL0("%s", #ptr);                                                                      \
            }                                                                                                          \
            POSTFAIL_INTERNAL();                                                                                       \
        }                                                                                                              \
    } while (0)

#define ASSERT_NOT_NULL(ptr, ...)                                                                                      \
    do {                                                                                                               \
        /* XXX: Some tests use ASSERT_NULL on ints... */                                                               \
        void *assert_p = (void *)(uintptr_t)(ptr);                                                                     \
        if (!assert_p) {                                                                                               \
            fprintf(AWS_TESTING_REPORT_FD, "%sExpected non-null but got null: ", FAIL_PREFIX);                         \
            if (!PRINT_FAIL_INTERNAL0(__VA_ARGS__)) {                                                                  \
                PRINT_FAIL_INTERNAL0("%s", #ptr);                                                                      \
            }                                                                                                          \
            POSTFAIL_INTERNAL();                                                                                       \
        }                                                                                                              \
    } while (0)

#define ASSERT_TYP_EQUALS(type, formatarg, expected, got, ...)                                                         \
    do {                                                                                                               \
        type assert_expected = (expected);                                                                             \
        type assert_actual = (got);                                                                                    \
        if (assert_expected != assert_actual) {                                                                        \
            fprintf(                                                                                                   \
                AWS_TESTING_REPORT_FD,                                                                                 \
                "%s" formatarg " != " formatarg ": ",                                                                  \
                FAIL_PREFIX,                                                                                           \
                assert_expected,                                                                                       \
                assert_actual);                                                                                        \
            if (!PRINT_FAIL_INTERNAL0(__VA_ARGS__)) {                                                                  \
                PRINT_FAIL_INTERNAL0("%s != %s", #expected, #got);                                                     \
            }                                                                                                          \
            POSTFAIL_INTERNAL();                                                                                       \
        }                                                                                                              \
    } while (0)

#ifdef _MSC_VER
#    define ASSERT_INT_EQUALS(expected, got, ...) ASSERT_TYP_EQUALS(intmax_t, "%lld", expected, got, __VA_ARGS__)
#    define ASSERT_UINT_EQUALS(expected, got, ...) ASSERT_TYP_EQUALS(uintmax_t, "%llu", expected, got, __VA_ARGS__)
#else
/* For comparing any signed integer types */
#    define ASSERT_INT_EQUALS(expected, got, ...) ASSERT_TYP_EQUALS(intmax_t, "%jd", expected, got, __VA_ARGS__)
/* For comparing any unsigned integer types */
#    define ASSERT_UINT_EQUALS(expected, got, ...) ASSERT_TYP_EQUALS(uintmax_t, "%ju", expected, got, __VA_ARGS__)
#endif

#define ASSERT_PTR_EQUALS(expected, got, ...)                                                                          \
    do {                                                                                                               \
        void *assert_expected = (void *)(uintptr_t)(expected);                                                         \
        void *assert_actual = (void *)(uintptr_t)(got);                                                                \
        if (assert_expected != assert_actual) {                                                                        \
            fprintf(AWS_TESTING_REPORT_FD, "%s%p != %p: ", FAIL_PREFIX, assert_expected, assert_actual);               \
            if (!PRINT_FAIL_INTERNAL0(__VA_ARGS__)) {                                                                  \
                PRINT_FAIL_INTERNAL0("%s != %s", #expected, #got);                                                     \
            }                                                                                                          \
            POSTFAIL_INTERNAL();                                                                                       \
        }                                                                                                              \
    } while (0)

/* note that uint8_t is promoted to unsigned int in varargs, so %02x is an acceptable format string */
#define ASSERT_BYTE_HEX_EQUALS(expected, got, ...) ASSERT_TYP_EQUALS(uint8_t, "%02X", expected, got, __VA_ARGS__)
#define ASSERT_HEX_EQUALS(expected, got, ...) ASSERT_TYP_EQUALS(unsigned long long, "%llX", expected, got, __VA_ARGS__)

#define ASSERT_STR_EQUALS(expected, got, ...)                                                                          \
    do {                                                                                                               \
        const char *assert_expected = (expected);                                                                      \
        const char *assert_got = (got);                                                                                \
        ASSERT_NOT_NULL(assert_expected);                                                                              \
        ASSERT_NOT_NULL(assert_got);                                                                                   \
        if (strcmp(assert_expected, assert_got) != 0) {                                                                \
            fprintf(                                                                                                   \
                AWS_TESTING_REPORT_FD, "%sExpected: \"%s\"; got: \"%s\": ", FAIL_PREFIX, assert_expected, assert_got); \
            if (!PRINT_FAIL_INTERNAL0(__VA_ARGS__)) {                                                                  \
                PRINT_FAIL_INTERNAL0("ASSERT_STR_EQUALS(%s, %s)", #expected, #got);                                    \
            }                                                                                                          \
            POSTFAIL_INTERNAL();                                                                                       \
        }                                                                                                              \
    } while (0)

#define ASSERT_BIN_ARRAYS_EQUALS(expected, expected_size, got, got_size, ...)                                          \
    do {                                                                                                               \
        const uint8_t *assert_ex_p = (const uint8_t *)(expected);                                                      \
        size_t assert_ex_s = (expected_size);                                                                          \
        const uint8_t *assert_got_p = (const uint8_t *)(got);                                                          \
        size_t assert_got_s = (got_size);                                                                              \
        if (assert_ex_s == 0 && assert_got_s == 0) {                                                                   \
            break;                                                                                                     \
        }                                                                                                              \
        if (assert_ex_s != assert_got_s) {                                                                             \
            fprintf(AWS_TESTING_REPORT_FD, "%sSize mismatch: %zu != %zu: ", FAIL_PREFIX, assert_ex_s, assert_got_s);   \
            if (!PRINT_FAIL_INTERNAL0(__VA_ARGS__)) {                                                                  \
                PRINT_FAIL_INTERNAL0(                                                                                  \
                    "ASSERT_BIN_ARRAYS_EQUALS(%s, %s, %s, %s)", #expected, #expected_size, #got, #got_size);           \
            }                                                                                                          \
            POSTFAIL_INTERNAL();                                                                                       \
        }                                                                                                              \
        if (memcmp(assert_ex_p, assert_got_p, assert_got_s) != 0) {                                                    \
            if (assert_got_s <= 1024) {                                                                                \
                for (size_t assert_i = 0; assert_i < assert_ex_s; ++assert_i) {                                        \
                    if (assert_ex_p[assert_i] != assert_got_p[assert_i]) {                                             \
                        fprintf(                                                                                       \
                            AWS_TESTING_REPORT_FD,                                                                     \
                            "%sMismatch at byte[%zu]: 0x%02X != 0x%02X: ",                                             \
                            FAIL_PREFIX,                                                                               \
                            assert_i,                                                                                  \
                            assert_ex_p[assert_i],                                                                     \
                            assert_got_p[assert_i]);                                                                   \
                        break;                                                                                         \
                    }                                                                                                  \
                }                                                                                                      \
            } else {                                                                                                   \
                fprintf(AWS_TESTING_REPORT_FD, "%sData mismatch: ", FAIL_PREFIX);                                      \
            }                                                                                                          \
            if (!PRINT_FAIL_INTERNAL0(__VA_ARGS__)) {                                                                  \
                PRINT_FAIL_INTERNAL0(                                                                                  \
                    "ASSERT_BIN_ARRAYS_EQUALS(%s, %s, %s, %s)", #expected, #expected_size, #got, #got_size);           \
            }                                                                                                          \
            POSTFAIL_INTERNAL();                                                                                       \
        }                                                                                                              \
    } while (0)

#define ASSERT_CURSOR_VALUE_CSTRING_EQUALS(cursor, cstring, ...)                                                       \
    do {                                                                                                               \
        const uint8_t *assert_ex_p = (const uint8_t *)((cursor).ptr);                                                  \
        size_t assert_ex_s = (cursor).len;                                                                             \
        const uint8_t *assert_got_p = (const uint8_t *)cstring;                                                        \
        size_t assert_got_s = strlen(cstring);                                                                         \
        if (assert_ex_s == 0 && assert_got_s == 0) {                                                                   \
            break;                                                                                                     \
        }                                                                                                              \
        if (assert_ex_s != assert_got_s) {                                                                             \
            fprintf(AWS_TESTING_REPORT_FD, "%sSize mismatch: %zu != %zu: \n", FAIL_PREFIX, assert_ex_s, assert_got_s); \
            fprintf(                                                                                                   \
                AWS_TESTING_REPORT_FD,                                                                                 \
                "%sGot: \"" PRInSTR "\"; Expected: \"%s\" \n",                                                         \
                FAIL_PREFIX,                                                                                           \
                AWS_BYTE_CURSOR_PRI(cursor),                                                                           \
                cstring);                                                                                              \
            if (!PRINT_FAIL_INTERNAL0(__VA_ARGS__)) {                                                                  \
                PRINT_FAIL_INTERNAL0("ASSERT_CURSOR_VALUE_STRING_EQUALS(%s, %s)", #cursor, #cstring);                  \
            }                                                                                                          \
            POSTFAIL_INTERNAL();                                                                                       \
        }                                                                                                              \
        if (memcmp(assert_ex_p, assert_got_p, assert_got_s) != 0) {                                                    \
            fprintf(                                                                                                   \
                AWS_TESTING_REPORT_FD,                                                                                 \
                "%sData mismatch; Got: \"" PRInSTR "\"; Expected: \"%s\" \n",                                          \
                FAIL_PREFIX,                                                                                           \
                AWS_BYTE_CURSOR_PRI(cursor),                                                                           \
                cstring);                                                                                              \
            if (!PRINT_FAIL_INTERNAL0(__VA_ARGS__)) {                                                                  \
                PRINT_FAIL_INTERNAL0("ASSERT_CURSOR_VALUE_STRING_EQUALS(%s, %s)", #cursor, #cstring);                  \
            }                                                                                                          \
            POSTFAIL_INTERNAL();                                                                                       \
        }                                                                                                              \
    } while (0)

#define ASSERT_CURSOR_VALUE_STRING_EQUALS(cursor, string, ...)                                                         \
    ASSERT_CURSOR_VALUE_CSTRING_EQUALS(cursor, aws_string_c_str(string));

typedef int(aws_test_before_fn)(struct aws_allocator *allocator, void *ctx);
typedef int(aws_test_run_fn)(struct aws_allocator *allocator, void *ctx);
typedef int(aws_test_after_fn)(struct aws_allocator *allocator, int setup_result, void *ctx);

struct aws_test_harness {
    aws_test_before_fn *on_before;
    aws_test_run_fn *run;
    aws_test_after_fn *on_after;
    void *ctx;
    const char *test_name;
    int suppress_memcheck;
};

#if defined(_WIN32)
#    include <windows.h>
static LONG WINAPI s_test_print_stack_trace(struct _EXCEPTION_POINTERS *exception_pointers) {
#    if !defined(AWS_HEADER_CHECKER)
    aws_backtrace_print(stderr, exception_pointers);
#    endif
    return EXCEPTION_EXECUTE_HANDLER;
}
#elif defined(AWS_HAVE_EXECINFO)
#    include <signal.h>
static void s_print_stack_trace(int sig, siginfo_t *sig_info, void *user_data) {
    (void)sig;
    (void)sig_info;
    (void)user_data;
#    if !defined(AWS_HEADER_CHECKER)
    aws_backtrace_print(stderr, sig_info);
#    endif
    exit(-1);
}
#endif

static inline int s_aws_run_test_case(struct aws_test_harness *harness) {
    AWS_ASSERT(harness->run);
/*
 * MSVC compiler has a weird interactive pop-up in debug whenever 'abort()' is called, which can be triggered
 * by hitting any aws_assert or aws_pre_condition, causing the CI to hang. So disable the pop-up in tests.
 */
#ifdef _MSC_VER
    _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
#endif

#if defined(_WIN32)
    SetUnhandledExceptionFilter(s_test_print_stack_trace);
    /* Set working directory to path to this exe */
    char cwd[512];
    DWORD len = GetModuleFileNameA(NULL, cwd, sizeof(cwd));
    DWORD idx = len - 1;
    while (idx && cwd[idx] != '\\') {
        idx--;
    }
    cwd[idx] = 0;
    SetCurrentDirectory(cwd);
#elif defined(AWS_HAVE_EXECINFO)
    struct sigaction sa;
    memset(&sa, 0, sizeof(struct sigaction));
    sigemptyset(&sa.sa_mask);

    sa.sa_flags = SA_NODEFER;
    sa.sa_sigaction = s_print_stack_trace;

    sigaction(SIGSEGV, &sa, NULL);
#endif

    /* track allocations and report leaks in tests, unless suppressed */
    struct aws_allocator *allocator = NULL;
    if (harness->suppress_memcheck) {
        allocator = aws_default_allocator();
    } else {
        allocator = aws_mem_tracer_new(aws_default_allocator(), NULL, AWS_MEMTRACE_STACKS, 8);
    }

    /* wire up a logger to stderr by default, may be replaced by some tests */
    struct aws_logger err_logger;
    struct aws_logger_standard_options options;
    options.file = AWS_TESTING_REPORT_FD;
    options.level = AWS_LL_TRACE;
    options.filename = NULL;
    aws_logger_init_standard(&err_logger, aws_default_allocator(), &options);
    aws_logger_set(&err_logger);

    int test_res = AWS_OP_ERR;
    int setup_res = AWS_OP_SUCCESS;
    if (harness->on_before) {
        setup_res = harness->on_before(allocator, harness->ctx);
    }

    if (!setup_res) {
        test_res = harness->run(allocator, harness->ctx);
    }

    if (harness->on_after) {
        test_res |= harness->on_after(allocator, setup_res, harness->ctx);
    }

    if (test_res != AWS_OP_SUCCESS && test_res != AWS_OP_SKIP) {
        goto fail;
    }

    if (!harness->suppress_memcheck) {
        /* Reset the logger, as test can set their own logger and clean it up,
         * but aws_mem_tracer_dump() needs a valid logger to be active */
        aws_logger_set(&err_logger);

        const size_t leaked_bytes = aws_mem_tracer_count(allocator);
        if (leaked_bytes) {
            aws_mem_tracer_dump(allocator);
            PRINT_FAIL_INTERNAL0("Test leaked memory: %zu bytes", leaked_bytes);
            goto fail;
        }

        aws_mem_tracer_destroy(allocator);
    }

    aws_logger_set(NULL);
    aws_logger_clean_up(&err_logger);

    if (test_res == AWS_OP_SUCCESS) {
        RETURN_SUCCESS("%s [ \033[32mOK\033[0m ]", harness->test_name);
    } else if (test_res == AWS_OP_SKIP) {
        RETURN_SKIP("%s [ \033[32mSKIP\033[0m ]", harness->test_name);
    }

fail:
    FAIL("%s [ \033[31mFAILED\033[0m ]", harness->test_name);
}

/* Enables terminal escape sequences for text coloring on Windows. */
/* https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences */
#ifdef _WIN32

#    include <Windows.h>

#    ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
#        define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
#    endif

static inline int enable_vt_mode(void) {
    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    if (hOut == INVALID_HANDLE_VALUE) {
        return AWS_OP_ERR;
    }

    DWORD dwMode = 0;
    if (!GetConsoleMode(hOut, &dwMode)) {
        return AWS_OP_ERR;
    }

    dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
    if (!SetConsoleMode(hOut, dwMode)) {
        return AWS_OP_ERR;
    }
    return AWS_OP_SUCCESS;
}

#else

static inline int enable_vt_mode(void) {
    return AWS_OP_ERR;
}

#endif

#define AWS_TEST_CASE_SUPRESSION(name, fn, s)                                                                          \
    static int fn(struct aws_allocator *allocator, void *ctx);                                                         \
    static struct aws_test_harness name##_test = {                                                                     \
        NULL,                                                                                                          \
        fn,                                                                                                            \
        NULL,                                                                                                          \
        NULL,                                                                                                          \
        #name,                                                                                                         \
        s,                                                                                                             \
    };                                                                                                                 \
    int name(int argc, char *argv[]) {                                                                                 \
        (void)argc, (void)argv;                                                                                        \
        return s_aws_run_test_case(&name##_test);                                                                      \
    }

#define AWS_TEST_CASE_FIXTURE_SUPPRESSION(name, b, fn, af, c, s)                                                       \
    static int b(struct aws_allocator *allocator, void *ctx);                                                          \
    static int fn(struct aws_allocator *allocator, void *ctx);                                                         \
    static int af(struct aws_allocator *allocator, int setup_result, void *ctx);                                       \
    static struct aws_test_harness name##_test = {                                                                     \
        b,                                                                                                             \
        fn,                                                                                                            \
        af,                                                                                                            \
        c,                                                                                                             \
        #name,                                                                                                         \
        s,                                                                                                             \
    };                                                                                                                 \
    int name(int argc, char *argv[]) {                                                                                 \
        (void)argc;                                                                                                    \
        (void)argv;                                                                                                    \
        return s_aws_run_test_case(&name##_test);                                                                      \
    }

#define AWS_TEST_CASE(name, fn) AWS_TEST_CASE_SUPRESSION(name, fn, 0)
#define AWS_TEST_CASE_FIXTURE(name, b, fn, af, c) AWS_TEST_CASE_FIXTURE_SUPPRESSION(name, b, fn, af, c, 0)

#endif /* AWS_TESTING_AWS_TEST_HARNESS_H */
