83 lines
2.5 KiB
C
83 lines
2.5 KiB
C
|
|
/**
|
||
|
|
* @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 <stdio.h>
|
||
|
|
#include <string.h>
|
||
|
|
|
||
|
|
#include <akbasic/error.h>
|
||
|
|
#include <akbasic/parser.h>
|
||
|
|
#include <akbasic/runtime.h>
|
||
|
|
#include <akbasic/scanner.h>
|
||
|
|
#include <akbasic/sink.h>
|
||
|
|
|
||
|
|
#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_
|