/** * @file harness.h * @brief A runtime wired to memory buffers, for tests that need a live one. * * The runtime is `static` because it carries every pool the interpreter owns and * will not fit on a default stack -- the same reason the driver's main() does it. */ #ifndef _AKBASIC_TEST_HARNESS_H_ #define _AKBASIC_TEST_HARNESS_H_ #include #include #include #include #include #include #include #include "testutil.h" static akbasic_Runtime HARNESS_RUNTIME; static akbasic_TextSink HARNESS_SINK; static akbasic_StdioSink HARNESS_SINKSTATE; static char HARNESS_OUTPUT[16384]; static FILE *HARNESS_OUT; static FILE *HARNESS_IN; /** * @brief Bring up a runtime whose output lands in HARNESS_OUTPUT. * @param input Text the sink will serve to readline; may be NULL for none. */ static akerr_ErrorContext AKERR_NOIGNORE *harness_start(const char *input) { PREPARE_ERROR(errctx); memset(HARNESS_OUTPUT, 0, sizeof(HARNESS_OUTPUT)); HARNESS_OUT = fmemopen(HARNESS_OUTPUT, sizeof(HARNESS_OUTPUT), "w"); FAIL_ZERO_RETURN(errctx, (HARNESS_OUT != NULL), AKERR_IO, "could not open the output buffer"); setvbuf(HARNESS_OUT, NULL, _IONBF, 0); if ( input != NULL ) { HARNESS_IN = fmemopen((void *)(uintptr_t)input, strlen(input), "r"); FAIL_ZERO_RETURN(errctx, (HARNESS_IN != NULL), AKERR_IO, "could not open the input buffer"); } else { HARNESS_IN = fmemopen((void *)(uintptr_t)"", 0, "r"); } PASS(errctx, akbasic_sink_init_stdio(&HARNESS_SINK, &HARNESS_SINKSTATE, HARNESS_OUT, HARNESS_IN)); PASS(errctx, akbasic_runtime_init(&HARNESS_RUNTIME, &HARNESS_SINK)); SUCCEED_RETURN(errctx); } __attribute__((unused)) static void harness_stop(void) { if ( HARNESS_OUT != NULL ) { fclose(HARNESS_OUT); HARNESS_OUT = NULL; } if ( HARNESS_IN != NULL ) { fclose(HARNESS_IN); HARNESS_IN = NULL; } } /** @brief Scan and parse one line, yielding its first statement. */ __attribute__((unused)) static akerr_ErrorContext AKERR_NOIGNORE *harness_parse(const char *line, akbasic_ASTLeaf **dest) { PREPARE_ERROR(errctx); akbasic_Parser parser; PASS(errctx, akbasic_scanner_zero(&HARNESS_RUNTIME)); PASS(errctx, akbasic_scanner_scan(&HARNESS_RUNTIME, line, NULL, 0)); PASS(errctx, akbasic_parser_init(&parser, &HARNESS_RUNTIME)); PASS(errctx, akbasic_parser_parse(&parser, dest)); SUCCEED_RETURN(errctx); } #endif // _AKBASIC_TEST_HARNESS_H_