forked from Mirror/wren
Merge pull request #273 from munificent/api-test
Add infrastructure to test embedding API.
This commit is contained in:
1
Makefile
1
Makefile
@ -34,6 +34,7 @@ clean:
|
||||
|
||||
# Run the tests against the debug build of Wren.
|
||||
test: debug
|
||||
@ $(MAKE) -f script/wren.mk MODE=debug test
|
||||
@ ./script/test.py $(suite)
|
||||
|
||||
# Take the contents of the scripts under builtin/ and copy them into their
|
||||
|
||||
@ -4,7 +4,7 @@ from __future__ import print_function
|
||||
|
||||
from collections import defaultdict
|
||||
from os import listdir
|
||||
from os.path import abspath, dirname, isdir, isfile, join, realpath, relpath, splitext
|
||||
from os.path import abspath, basename, dirname, isdir, isfile, join, realpath, relpath, splitext
|
||||
import re
|
||||
from subprocess import Popen, PIPE
|
||||
import sys
|
||||
@ -12,6 +12,7 @@ import sys
|
||||
# Runs the tests.
|
||||
WREN_DIR = dirname(dirname(realpath(__file__)))
|
||||
WREN_APP = join(WREN_DIR, 'bin', 'wrend')
|
||||
TEST_APP = join(WREN_DIR, 'build', 'debug', 'test', 'wrend')
|
||||
|
||||
EXPECT_PATTERN = re.compile(r'// expect: (.*)')
|
||||
EXPECT_ERROR_PATTERN = re.compile(r'// expect error')
|
||||
@ -72,7 +73,7 @@ def print_line(line=None):
|
||||
sys.stdout.flush()
|
||||
|
||||
|
||||
def run_test(path, example=False):
|
||||
def run_script(app, path, type):
|
||||
global passed
|
||||
global failed
|
||||
global skipped
|
||||
@ -155,7 +156,12 @@ def run_test(path, example=False):
|
||||
input_bytes = "".join(input_lines).encode("utf-8")
|
||||
|
||||
# Invoke wren and run the test.
|
||||
proc = Popen([WREN_APP, path], stdin=PIPE, stdout=PIPE, stderr=PIPE)
|
||||
test_arg = path
|
||||
if type == "api test":
|
||||
# Just pass the suite name to API tests.
|
||||
test_arg = basename(splitext(test_arg)[0])
|
||||
|
||||
proc = Popen([app, test_arg], stdin=PIPE, stdout=PIPE, stderr=PIPE)
|
||||
(out, err) = proc.communicate(input_bytes)
|
||||
|
||||
fails = []
|
||||
@ -223,7 +229,9 @@ def run_test(path, example=False):
|
||||
for line in out_lines:
|
||||
if sys.version_info < (3, 0):
|
||||
line = line.encode('utf-8')
|
||||
if example:
|
||||
|
||||
if type == "example":
|
||||
# Ignore output from examples.
|
||||
pass
|
||||
elif expect_index >= len(expect_output):
|
||||
fails.append('Got output "{0}" when none was expected.'.format(line))
|
||||
@ -251,10 +259,21 @@ def run_test(path, example=False):
|
||||
print(' ' + color.PINK + fail + color.DEFAULT)
|
||||
print('')
|
||||
|
||||
def run_example(path):
|
||||
return run_test(path, example=True)
|
||||
|
||||
walk(join(WREN_DIR, 'test'), run_test, ignored=['benchmark'])
|
||||
def run_test(path, example=False):
|
||||
run_script(WREN_APP, path, "test")
|
||||
|
||||
|
||||
def run_api_test(path):
|
||||
run_script(TEST_APP, path, "api test")
|
||||
|
||||
|
||||
def run_example(path):
|
||||
run_script(WREN_APP, path, "example")
|
||||
|
||||
|
||||
walk(join(WREN_DIR, 'test'), run_test, ignored=['api', 'benchmark'])
|
||||
walk(join(WREN_DIR, 'test', 'api'), run_api_test)
|
||||
walk(join(WREN_DIR, 'example'), run_example)
|
||||
|
||||
print_line()
|
||||
|
||||
@ -23,6 +23,7 @@ CLI_HEADERS := $(wildcard src/cli/*.h)
|
||||
VM_HEADERS := $(wildcard src/vm/*.h)
|
||||
CLI_SOURCES := $(wildcard src/cli/*.c)
|
||||
VM_SOURCES := $(wildcard src/vm/*.c)
|
||||
TEST_SOURCES := $(shell find test/api -name '*.c')
|
||||
BUILD_DIR := build
|
||||
|
||||
C_WARNINGS := -Wall -Wextra -Werror -Wno-unused-parameter
|
||||
@ -93,37 +94,58 @@ endif
|
||||
|
||||
CFLAGS := $(C_OPTIONS) $(C_WARNINGS)
|
||||
|
||||
CLI_OBJECTS := $(addprefix $(BUILD_DIR)/cli/, $(notdir $(CLI_SOURCES:.c=.o)))
|
||||
VM_OBJECTS := $(addprefix $(BUILD_DIR)/vm/, $(notdir $(VM_SOURCES:.c=.o)))
|
||||
CLI_OBJECTS := $(addprefix $(BUILD_DIR)/cli/, $(notdir $(CLI_SOURCES:.c=.o)))
|
||||
VM_OBJECTS := $(addprefix $(BUILD_DIR)/vm/, $(notdir $(VM_SOURCES:.c=.o)))
|
||||
TEST_OBJECTS := $(patsubst test/api/%.c, $(BUILD_DIR)/test/%.o, $(TEST_SOURCES))
|
||||
|
||||
# Targets ---------------------------------------------------------------------
|
||||
|
||||
all: prep bin/$(WREN) lib/lib$(WREN).a lib/lib$(WREN).$(SHARED_EXT)
|
||||
# Builds the VM libraries and CLI interpreter.
|
||||
all: bin/$(WREN) lib/lib$(WREN).a lib/lib$(WREN).$(SHARED_EXT)
|
||||
|
||||
prep:
|
||||
@mkdir -p bin lib $(BUILD_DIR)/cli $(BUILD_DIR)/vm
|
||||
# Builds the API test executable.
|
||||
test: $(BUILD_DIR)/test/$(WREN)
|
||||
|
||||
# Command-line interpreter.
|
||||
bin/$(WREN): $(CLI_OBJECTS) $(VM_OBJECTS)
|
||||
@printf "%10s %-30s %s\n" $(CC) $@ "$(C_OPTIONS)"
|
||||
@$(CC) $(CFLAGS) -Isrc/include -o $@ $^ -lm
|
||||
@mkdir -p bin
|
||||
@$(CC) $(CFLAGS) -o $@ $^ -lm
|
||||
|
||||
# Static library.
|
||||
lib/lib$(WREN).a: $(VM_OBJECTS)
|
||||
@printf "%10s %-30s %s\n" $(AR) $@ "rcu"
|
||||
@mkdir -p lib
|
||||
@$(AR) rcu $@ $^
|
||||
|
||||
# Shared library.
|
||||
lib/lib$(WREN).$(SHARED_EXT): $(VM_OBJECTS)
|
||||
@printf "%10s %-30s %s\n" $(CC) $@ "$(C_OPTIONS) $(SHARED_LIB_FLAGS)"
|
||||
@mkdir -p lib
|
||||
@$(CC) $(CFLAGS) -shared $(SHARED_LIB_FLAGS) -o $@ $^
|
||||
|
||||
# Test executable.
|
||||
$(BUILD_DIR)/test/$(WREN): $(TEST_OBJECTS) $(VM_OBJECTS) $(BUILD_DIR)/cli/io.o $(BUILD_DIR)/cli/vm.o
|
||||
@printf "%10s %-30s %s\n" $(CC) $@ "$(C_OPTIONS)"
|
||||
@mkdir -p $(BUILD_DIR)/test
|
||||
@$(CC) $(CFLAGS) -o $@ $^ -lm
|
||||
|
||||
# CLI object files.
|
||||
$(BUILD_DIR)/cli/%.o: src/cli/%.c $(CLI_HEADERS) $(VM_HEADERS)
|
||||
@printf "%10s %-30s %s\n" $(CC) $< "$(C_OPTIONS)"
|
||||
@mkdir -p $(BUILD_DIR)/cli
|
||||
@$(CC) -c $(CFLAGS) -Isrc/include -o $@ $(FILE_FLAG) $<
|
||||
|
||||
# VM object files.
|
||||
$(BUILD_DIR)/vm/%.o: src/vm/%.c $(VM_HEADERS)
|
||||
@printf "%10s %-30s %s\n" $(CC) $< "$(C_OPTIONS)"
|
||||
@mkdir -p $(BUILD_DIR)/vm
|
||||
@$(CC) -c $(CFLAGS) -Isrc/include -o $@ $(FILE_FLAG) $<
|
||||
|
||||
# Test object files.
|
||||
$(BUILD_DIR)/test/%.o: test/api/%.c $(VM_HEADERS)
|
||||
@printf "%10s %-30s %s\n" $(CC) $< "$(C_OPTIONS)"
|
||||
@mkdir -p $(dir $@)
|
||||
@$(CC) -c $(CFLAGS) -Isrc/include -Isrc/cli -o $@ $(FILE_FLAG) $<
|
||||
|
||||
.PHONY: all test
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
|
||||
static int runRepl()
|
||||
{
|
||||
WrenVM* vm = createVM();
|
||||
WrenVM* vm = createVM(NULL);
|
||||
|
||||
printf("\\\\/\"-\n");
|
||||
printf(" \\_/ wren v0.0.0\n");
|
||||
@ -50,7 +50,7 @@ int main(int argc, const char* argv[])
|
||||
}
|
||||
else if (argc == 2)
|
||||
{
|
||||
runFile(argv[1]);
|
||||
runFile(NULL, argv[1]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@ -4,11 +4,11 @@
|
||||
#include "io.h"
|
||||
#include "vm.h"
|
||||
|
||||
WrenVM* createVM()
|
||||
WrenVM* createVM(WrenBindForeignMethodFn bindForeign)
|
||||
{
|
||||
WrenConfiguration config;
|
||||
|
||||
config.bindForeignMethodFn = NULL;
|
||||
config.bindForeignMethodFn = bindForeign;
|
||||
config.loadModuleFn = readModule;
|
||||
|
||||
// Since we're running in a standalone process, be generous with memory.
|
||||
@ -22,7 +22,7 @@ WrenVM* createVM()
|
||||
return wrenNewVM(&config);
|
||||
}
|
||||
|
||||
void runFile(const char* path)
|
||||
void runFile(WrenBindForeignMethodFn bindForeign, const char* path)
|
||||
{
|
||||
// Use the directory where the file is as the root to resolve imports
|
||||
// relative to.
|
||||
@ -42,7 +42,7 @@ void runFile(const char* path)
|
||||
exit(66);
|
||||
}
|
||||
|
||||
WrenVM* vm = createVM();
|
||||
WrenVM* vm = createVM(bindForeign);
|
||||
|
||||
WrenInterpretResult result = wrenInterpret(vm, path, source);
|
||||
|
||||
|
||||
@ -4,11 +4,11 @@
|
||||
#include "wren.h"
|
||||
|
||||
// Creates a new Wren VM with the CLI's module loader and other configuration.
|
||||
WrenVM* createVM();
|
||||
WrenVM* createVM(WrenBindForeignMethodFn bindForeign);
|
||||
|
||||
// Executes the Wren script at [path] in a new VM.
|
||||
//
|
||||
// Exits if the script failed or could not be loaded.
|
||||
void runFile(const char* path);
|
||||
void runFile(WrenBindForeignMethodFn bindForeign, const char* path);
|
||||
|
||||
#endif
|
||||
|
||||
58
test/api/main.c
Normal file
58
test/api/main.c
Normal file
@ -0,0 +1,58 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "io.h"
|
||||
#include "vm.h"
|
||||
#include "wren.h"
|
||||
|
||||
#include "return_bool/return_bool.h"
|
||||
|
||||
// The name of the currently executing API test.
|
||||
const char* testName;
|
||||
|
||||
static WrenForeignMethodFn bindForeign(
|
||||
WrenVM* vm, const char* module, const char* className,
|
||||
bool isStatic, const char* signature)
|
||||
{
|
||||
if (strcmp(module, "main") != 0) return NULL;
|
||||
|
||||
// For convenience, concatenate all of the method qualifiers into a single
|
||||
// signature string.
|
||||
char fullName[256];
|
||||
fullName[0] = '\0';
|
||||
if (isStatic) strcat(fullName, "static ");
|
||||
strcat(fullName, className);
|
||||
strcat(fullName, ".");
|
||||
strcat(fullName, signature);
|
||||
|
||||
if (strcmp(testName, "return_bool") == 0)
|
||||
{
|
||||
return returnBoolBindForeign(fullName);
|
||||
}
|
||||
|
||||
fprintf(stderr,
|
||||
"Unknown foreign method '%s' for test '%s'\n", fullName, testName);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
if (argc != 2)
|
||||
{
|
||||
fprintf(stderr, "Usage: wren <test>\n");
|
||||
return 64; // EX_USAGE.
|
||||
}
|
||||
|
||||
testName = argv[1];
|
||||
|
||||
// The test script is at "test/api/<test>/<test>.wren".
|
||||
char testPath[256];
|
||||
strcpy(testPath, "test/api/");
|
||||
strcat(testPath, testName);
|
||||
strcat(testPath, "/");
|
||||
strcat(testPath, testName);
|
||||
strcat(testPath, ".wren");
|
||||
|
||||
runFile(bindForeign, testPath);
|
||||
return 0;
|
||||
}
|
||||
21
test/api/return_bool/return_bool.c
Normal file
21
test/api/return_bool/return_bool.c
Normal file
@ -0,0 +1,21 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "wren.h"
|
||||
|
||||
static void returnTrue(WrenVM* vm)
|
||||
{
|
||||
wrenReturnBool(vm, true);
|
||||
}
|
||||
|
||||
static void returnFalse(WrenVM* vm)
|
||||
{
|
||||
wrenReturnBool(vm, false);
|
||||
}
|
||||
|
||||
WrenForeignMethodFn returnBoolBindForeign(const char* signature)
|
||||
{
|
||||
if (strcmp(signature, "static Api.returnTrue") == 0) return returnTrue;
|
||||
if (strcmp(signature, "static Api.returnFalse") == 0) return returnFalse;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
3
test/api/return_bool/return_bool.h
Normal file
3
test/api/return_bool/return_bool.h
Normal file
@ -0,0 +1,3 @@
|
||||
#include "wren.h"
|
||||
|
||||
WrenForeignMethodFn returnBoolBindForeign(const char* signature);
|
||||
7
test/api/return_bool/return_bool.wren
Normal file
7
test/api/return_bool/return_bool.wren
Normal file
@ -0,0 +1,7 @@
|
||||
class Api {
|
||||
foreign static returnTrue
|
||||
foreign static returnFalse
|
||||
}
|
||||
|
||||
IO.print(Api.returnTrue) // expect: true
|
||||
IO.print(Api.returnFalse) // expect: false
|
||||
Reference in New Issue
Block a user