mirror of
https://github.com/extism/extism.git
synced 2026-01-09 13:57:55 -05:00
test: add more host function tests, cleanup tests to use wasm/code.wasm when possible (#219)
This commit is contained in:
4
.github/workflows/ci-go.yml
vendored
4
.github/workflows/ci-go.yml
vendored
@@ -34,6 +34,6 @@ jobs:
|
||||
- name: Test Go Host SDK
|
||||
run: |
|
||||
go version
|
||||
cd go
|
||||
LD_LIBRARY_PATH=/usr/local/lib go run main.go
|
||||
LD_LIBRARY_PATH=/usr/local/lib go test
|
||||
cd go
|
||||
LD_LIBRARY_PATH=/usr/local/lib go run main.go | grep "Hello from Go!"
|
||||
|
||||
@@ -13,3 +13,4 @@ build-test:
|
||||
.PHONY: test
|
||||
test: build-test
|
||||
cd test && ./test
|
||||
|
||||
|
||||
Binary file not shown.
@@ -10,6 +10,8 @@ std::vector<uint8_t> read(const char *filename) {
|
||||
std::istreambuf_iterator<char>());
|
||||
}
|
||||
|
||||
const std::string code = "../../wasm/code.wasm";
|
||||
|
||||
namespace {
|
||||
using namespace extism;
|
||||
|
||||
@@ -20,7 +22,7 @@ TEST(Context, Basic) {
|
||||
|
||||
TEST(Plugin, Manifest) {
|
||||
Context context;
|
||||
Manifest manifest = Manifest::path("code.wasm");
|
||||
Manifest manifest = Manifest::path(code);
|
||||
manifest.set_config("a", "1");
|
||||
|
||||
ASSERT_NO_THROW(Plugin plugin = context.plugin(manifest));
|
||||
@@ -38,7 +40,7 @@ TEST(Plugin, BadManifest) {
|
||||
|
||||
TEST(Plugin, Bytes) {
|
||||
Context context;
|
||||
auto wasm = read("code.wasm");
|
||||
auto wasm = read(code.c_str());
|
||||
ASSERT_NO_THROW(Plugin plugin = context.plugin(wasm));
|
||||
Plugin plugin = context.plugin(wasm);
|
||||
|
||||
@@ -48,7 +50,7 @@ TEST(Plugin, Bytes) {
|
||||
|
||||
TEST(Plugin, UpdateConfig) {
|
||||
Context context;
|
||||
auto wasm = read("code.wasm");
|
||||
auto wasm = read(code.c_str());
|
||||
Plugin plugin = context.plugin(wasm);
|
||||
|
||||
Config config;
|
||||
@@ -58,13 +60,34 @@ TEST(Plugin, UpdateConfig) {
|
||||
|
||||
TEST(Plugin, FunctionExists) {
|
||||
Context context;
|
||||
auto wasm = read("code.wasm");
|
||||
auto wasm = read(code.c_str());
|
||||
Plugin plugin = context.plugin(wasm);
|
||||
|
||||
ASSERT_FALSE(plugin.function_exists("bad_function"));
|
||||
ASSERT_TRUE(plugin.function_exists("count_vowels"));
|
||||
}
|
||||
|
||||
TEST(Plugin, HostFunction) {
|
||||
Context context;
|
||||
auto wasm = read("../../wasm/code-functions.wasm");
|
||||
auto t = std::vector<ValType>{ValType::I64};
|
||||
Function hello_world =
|
||||
Function("hello_world", t, t,
|
||||
[](CurrentPlugin plugin, const std::vector<Val> ¶ms,
|
||||
std::vector<Val> &results, void *user_data) {
|
||||
auto offs = plugin.alloc(4);
|
||||
memcpy(plugin.memory() + offs, "test", 4);
|
||||
results[0].v.i64 = (int64_t)offs;
|
||||
});
|
||||
auto functions = std::vector<Function>{
|
||||
hello_world,
|
||||
};
|
||||
Plugin plugin = context.plugin(wasm, true, functions);
|
||||
auto buf = plugin.call("count_vowels", "aaa");
|
||||
ASSERT_EQ(buf.length, 4);
|
||||
ASSERT_EQ((std::string)buf, "test");
|
||||
}
|
||||
|
||||
}; // namespace
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
(ocaml (>= 4.14.1))
|
||||
(dune (>= 3.2))
|
||||
(ppx_yojson_conv (>= 0.15.0))
|
||||
(ppx_inline_test (>= 0.15.0))
|
||||
(base64 (>= 3.5.0))
|
||||
)
|
||||
(tags
|
||||
|
||||
@@ -7,12 +7,13 @@ authors: ["Extism Authors <oss@extism.org>"]
|
||||
license: "BSD-3-Clause"
|
||||
tags: ["topics" "wasm" "plugin"]
|
||||
homepage: "https://github.com/extism/extism"
|
||||
doc: "https://extism.org"
|
||||
doc: "https://github.com/extism/extism"
|
||||
bug-reports: "https://github.com/extism/extism/issues"
|
||||
depends: [
|
||||
"ocaml" {>= "4.14.1"}
|
||||
"dune" {>= "3.2" & >= "3.2"}
|
||||
"ppx_yojson_conv" {>= "0.15.0"}
|
||||
"ppx_inline_test" {>= "0.15.0"}
|
||||
"base64" {>= "3.5.0"}
|
||||
"odoc" {with-doc}
|
||||
]
|
||||
|
||||
100
extism.go
100
extism.go
@@ -14,6 +14,41 @@ import (
|
||||
#cgo LDFLAGS: -L/usr/local/lib -lextism
|
||||
#include <extism.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int64_t extism_val_i64(ExtismValUnion* x){
|
||||
return x->i64;
|
||||
}
|
||||
|
||||
int32_t extism_val_i32(ExtismValUnion* x){
|
||||
return x->i32;
|
||||
}
|
||||
|
||||
float extism_val_f32(ExtismValUnion* x){
|
||||
return x->f32;
|
||||
}
|
||||
|
||||
double extism_val_f64(ExtismValUnion* x){
|
||||
return x->f64;
|
||||
}
|
||||
|
||||
|
||||
void extism_val_set_i64(ExtismValUnion* x, int64_t i){
|
||||
x->i64 = i;
|
||||
}
|
||||
|
||||
|
||||
void extism_val_set_i32(ExtismValUnion* x, int32_t i){
|
||||
x->i32 = i;
|
||||
}
|
||||
|
||||
void extism_val_set_f32(ExtismValUnion* x, float f){
|
||||
x->f32 = f;
|
||||
}
|
||||
|
||||
void extism_val_set_f64(ExtismValUnion* x, double f){
|
||||
x->f64 = f;
|
||||
}
|
||||
|
||||
*/
|
||||
import "C"
|
||||
|
||||
@@ -33,6 +68,7 @@ var (
|
||||
I64 ValType = C.I64
|
||||
F32 ValType = C.F32
|
||||
F64 ValType = C.F64
|
||||
V128 ValType = C.V128
|
||||
FuncRef ValType = C.FuncRef
|
||||
ExternRef ValType = C.ExternRef
|
||||
)
|
||||
@@ -75,9 +111,9 @@ type CurrentPlugin struct {
|
||||
pointer *C.ExtismCurrentPlugin
|
||||
}
|
||||
|
||||
func GetCurrentPlugin(ptr *C.ExtismCurrentPlugin) CurrentPlugin {
|
||||
func GetCurrentPlugin(ptr unsafe.Pointer) CurrentPlugin {
|
||||
return CurrentPlugin{
|
||||
pointer: ptr,
|
||||
pointer: (*C.ExtismCurrentPlugin)(ptr),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,6 +123,21 @@ func (p *CurrentPlugin) Memory(offs uint) []byte {
|
||||
return unsafe.Slice((*byte)(unsafe.Add(data, offs)), C.int(length))
|
||||
}
|
||||
|
||||
// Alloc a new memory block of the given length, returning its offset
|
||||
func (p *CurrentPlugin) Alloc(n uint) uint {
|
||||
return uint(C.extism_current_plugin_memory_alloc(p.pointer, C.uint64_t(n)))
|
||||
}
|
||||
|
||||
// Free the memory block specified by the given offset
|
||||
func (p *CurrentPlugin) Free(offs uint) {
|
||||
C.extism_current_plugin_memory_free(p.pointer, C.uint64_t(offs))
|
||||
}
|
||||
|
||||
// Length returns the number of bytes allocated at the specified offset
|
||||
func (p *CurrentPlugin) Length(offs uint) uint {
|
||||
return uint(C.extism_current_plugin_memory_length(p.pointer, C.uint64_t(offs)))
|
||||
}
|
||||
|
||||
// NewContext creates a new context, it should be freed using the `Free` method
|
||||
func NewContext() Context {
|
||||
p := C.extism_context_new()
|
||||
@@ -360,3 +411,48 @@ func (plugin *Plugin) Free() {
|
||||
func (ctx Context) Reset() {
|
||||
C.extism_context_reset(ctx.pointer)
|
||||
}
|
||||
|
||||
// ValGetI64 returns an I64 from an ExtismVal, it accepts a pointer to a C.ExtismVal
|
||||
func ValGetI64(v unsafe.Pointer) int64 {
|
||||
return int64(C.extism_val_i64(&(*Val)(v).v))
|
||||
}
|
||||
|
||||
// ValGetUInt returns a uint from an ExtismVal, it accepts a pointer to a C.ExtismVal
|
||||
func ValGetUInt(v unsafe.Pointer) uint {
|
||||
return uint(C.extism_val_i64(&(*Val)(v).v))
|
||||
}
|
||||
|
||||
// ValGetI32 returns an int32 from an ExtismVal, it accepts a pointer to a C.ExtismVal
|
||||
func ValGetI32(v unsafe.Pointer) int32 {
|
||||
return int32(C.extism_val_i32(&(*Val)(v).v))
|
||||
}
|
||||
|
||||
// ValGetF32 returns a float32 from an ExtismVal, it accepts a pointer to a C.ExtismVal
|
||||
func ValGetF32(v unsafe.Pointer) float32 {
|
||||
return float32(C.extism_val_f32(&(*Val)(v).v))
|
||||
}
|
||||
|
||||
// ValGetF32 returns a float64 from an ExtismVal, it accepts a pointer to a C.ExtismVal
|
||||
func ValGetF64(v unsafe.Pointer) float64 {
|
||||
return float64(C.extism_val_i64(&(*Val)(v).v))
|
||||
}
|
||||
|
||||
// ValSetI64 stores an int64 in an ExtismVal, it accepts a pointer to a C.ExtismVal and the new value
|
||||
func ValSetI64(v unsafe.Pointer, i int64) {
|
||||
C.extism_val_set_i64(&(*Val)(v).v, C.int64_t(i))
|
||||
}
|
||||
|
||||
// ValSetI32 stores an int32 in an ExtismVal, it accepts a pointer to a C.ExtismVal and the new value
|
||||
func ValSetI32(v unsafe.Pointer, i int32) {
|
||||
C.extism_val_set_i32(&(*Val)(v).v, C.int32_t(i))
|
||||
}
|
||||
|
||||
// ValSetF32 stores a float32 in an ExtismVal, it accepts a pointer to a C.ExtismVal and the new value
|
||||
func ValSetF32(v unsafe.Pointer, i float32) {
|
||||
C.extism_val_set_f32(&(*Val)(v).v, C.float(i))
|
||||
}
|
||||
|
||||
// ValSetF64 stores a float64 in an ExtismVal, it accepts a pointer to a C.ExtismVal and the new value
|
||||
func ValSetF64(v unsafe.Pointer, f float64) {
|
||||
C.extism_val_set_f64(&(*Val)(v).v, C.double(f))
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ authors: ["Extism Authors <oss@extism.org>"]
|
||||
license: "BSD-3-Clause"
|
||||
tags: ["topics" "wasm" "plugin"]
|
||||
homepage: "https://github.com/extism/extism"
|
||||
doc: "https://extism.org"
|
||||
doc: "https://github.com/extism/extism"
|
||||
bug-reports: "https://github.com/extism/extism/issues"
|
||||
depends: [
|
||||
"ocaml" {>= "4.14.1"}
|
||||
@@ -35,3 +35,5 @@ build: [
|
||||
]
|
||||
]
|
||||
dev-repo: "git+https://github.com/extism/extism.git"
|
||||
build-env: [EXTISM_TEST_NO_LIB = ""]
|
||||
post-messages: ["See https://extism.org/docs/install/ for information about installing libextism"]
|
||||
|
||||
2
extism.opam.template
Normal file
2
extism.opam.template
Normal file
@@ -0,0 +1,2 @@
|
||||
build-env: [EXTISM_TEST_NO_LIB = ""]
|
||||
post-messages: ["See https://extism.org/docs/install/ for information about installing libextism"]
|
||||
@@ -6,11 +6,16 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func manifest() Manifest {
|
||||
func manifest(functions bool) Manifest {
|
||||
path := "./wasm/code.wasm"
|
||||
if functions {
|
||||
path = "./wasm/code-functions.wasm"
|
||||
}
|
||||
|
||||
return Manifest{
|
||||
Wasm: []Wasm{
|
||||
WasmFile{
|
||||
Path: "./wasm/code.wasm",
|
||||
Path: path,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -38,7 +43,7 @@ func TestCallPlugin(t *testing.T) {
|
||||
ctx := NewContext()
|
||||
defer ctx.Free()
|
||||
|
||||
plugin, err := ctx.PluginFromManifest(manifest(), false)
|
||||
plugin, err := ctx.PluginFromManifest(manifest(false), []Function{}, false)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -58,7 +63,7 @@ func TestFreePlugin(t *testing.T) {
|
||||
ctx := NewContext()
|
||||
defer ctx.Free()
|
||||
|
||||
plugin, err := ctx.PluginFromManifest(manifest(), false)
|
||||
plugin, err := ctx.PluginFromManifest(manifest(false), []Function{}, false)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -78,7 +83,7 @@ func TestContextReset(t *testing.T) {
|
||||
ctx := NewContext()
|
||||
defer ctx.Free()
|
||||
|
||||
plugin, err := ctx.PluginFromManifest(manifest(), false)
|
||||
plugin, err := ctx.PluginFromManifest(manifest(false), []Function{}, false)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -98,7 +103,7 @@ func TestCanUpdateAManifest(t *testing.T) {
|
||||
ctx := NewContext()
|
||||
defer ctx.Free()
|
||||
|
||||
plugin, err := ctx.PluginFromManifest(manifest(), false)
|
||||
plugin, err := ctx.PluginFromManifest(manifest(false), []Function{}, false)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -107,7 +112,7 @@ func TestCanUpdateAManifest(t *testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
plugin.UpdateManifest(manifest(), false)
|
||||
plugin.UpdateManifest(manifest(false), []Function{}, false)
|
||||
|
||||
// can still call the plugin
|
||||
if err := expectVowelCount(plugin, "this is a test", 4); err != nil {
|
||||
@@ -119,7 +124,7 @@ func TestFunctionExists(t *testing.T) {
|
||||
ctx := NewContext()
|
||||
defer ctx.Free()
|
||||
|
||||
plugin, err := ctx.PluginFromManifest(manifest(), false)
|
||||
plugin, err := ctx.PluginFromManifest(manifest(false), []Function{}, false)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -136,7 +141,7 @@ func TestErrorsOnUnknownFunction(t *testing.T) {
|
||||
ctx := NewContext()
|
||||
defer ctx.Free()
|
||||
|
||||
plugin, err := ctx.PluginFromManifest(manifest(), false)
|
||||
plugin, err := ctx.PluginFromManifest(manifest(false), []Function{}, false)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -17,12 +17,18 @@ EXTISM_GO_FUNCTION(hello_world);
|
||||
import "C"
|
||||
|
||||
//export hello_world
|
||||
func hello_world(plugin *C.ExtismCurrentPlugin, inputs *C.ExtismVal, nInputs C.ExtismSize, outputs *C.ExtismVal, nOutputs C.ExtismSize, userData uintptr) {
|
||||
func hello_world(plugin unsafe.Pointer, inputs *C.ExtismVal, nInputs C.ExtismSize, outputs *C.ExtismVal, nOutputs C.ExtismSize, userData uintptr) {
|
||||
fmt.Println("Hello from Go!")
|
||||
s := cgo.Handle(userData)
|
||||
fmt.Println(s.Value().(string))
|
||||
inputSlice := unsafe.Slice(inputs, nInputs)
|
||||
outputSlice := unsafe.Slice(outputs, nOutputs)
|
||||
|
||||
// Get memory pointed to by first element of input slice
|
||||
p := extism.GetCurrentPlugin(plugin)
|
||||
mem := p.Memory(extism.ValGetUInt(unsafe.Pointer(&inputSlice[0])))
|
||||
fmt.Println(string(mem))
|
||||
|
||||
outputSlice[0] = inputSlice[0]
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ unwrap (Right x) = return x
|
||||
unwrap (Left (ExtismError msg)) =
|
||||
assertFailure msg
|
||||
|
||||
defaultManifest = manifest [wasmFile "test/code.wasm"]
|
||||
defaultManifest = manifest [wasmFile "../../wasm/code.wasm"]
|
||||
|
||||
initPlugin :: Context -> IO Plugin
|
||||
initPlugin context =
|
||||
|
||||
Binary file not shown.
@@ -87,6 +87,7 @@ export enum ValType {
|
||||
I64,
|
||||
F32,
|
||||
F64,
|
||||
V128,
|
||||
FuncRef,
|
||||
ExternRef,
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -2,14 +2,23 @@ import * as extism from "../src/index";
|
||||
import { readFileSync } from "fs";
|
||||
import { join } from "path";
|
||||
|
||||
function manifest(): extism.Manifest {
|
||||
function manifest(functions: boolean = false): extism.Manifest {
|
||||
return {
|
||||
wasm: [{ path: join(__dirname, "/code.wasm") }],
|
||||
wasm: [
|
||||
{
|
||||
path: join(
|
||||
__dirname,
|
||||
functions
|
||||
? "/../../wasm/code-functions.wasm"
|
||||
: "/../../wasm/code.wasm"
|
||||
),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
function wasmBuffer(): Buffer {
|
||||
return readFileSync(join(__dirname, "/code.wasm"));
|
||||
return readFileSync(join(__dirname, "/../../wasm/code.wasm"));
|
||||
}
|
||||
|
||||
describe("test extism", () => {
|
||||
@@ -102,4 +111,27 @@ describe("test extism", () => {
|
||||
).rejects.toMatch(/Plugin error/);
|
||||
});
|
||||
});
|
||||
|
||||
test("host functions work", async () => {
|
||||
await extism.withContext(async (ctx: extism.Context) => {
|
||||
const plugin = ctx.plugin(manifest(true), true, [
|
||||
new extism.HostFunction(
|
||||
"hello_world",
|
||||
[extism.ValType.I64],
|
||||
[extism.ValType.I64],
|
||||
(plugin: any, params: any, results: any, user_data: string) => {
|
||||
const offs = plugin.memoryAlloc(user_data.length);
|
||||
const mem = plugin.memory(offs);
|
||||
mem.write(user_data);
|
||||
results[0].v.i64 = offs;
|
||||
},
|
||||
"test"
|
||||
),
|
||||
]);
|
||||
|
||||
const res = await plugin.call("count_vowels", "aaa");
|
||||
|
||||
expect(res.toString()).toBe("test");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -27,7 +27,16 @@ let locate () =
|
||||
init paths
|
||||
|> function
|
||||
| Some x -> x
|
||||
| None -> raise Not_found
|
||||
| None -> (
|
||||
let fail n =
|
||||
Printf.fprintf stderr
|
||||
"Unable to find Extism installation, see \
|
||||
https://extism.org/docs/install/ for installation instructions\n";
|
||||
exit n
|
||||
in
|
||||
match Sys.getenv_opt "EXTISM_TEST_NO_LIB" with
|
||||
| None -> fail 1
|
||||
| Some _ -> fail 0)
|
||||
|
||||
let from =
|
||||
let filename = locate () in
|
||||
@@ -41,23 +50,25 @@ let extism_context_new = fn "extism_context_new" (void @-> returning context)
|
||||
let extism_context_free = fn "extism_context_free" (context @-> returning void)
|
||||
|
||||
module Extism_val_type = struct
|
||||
type t = I32 | I64 | F32 | F64 | FuncRef | ExternRef
|
||||
type t = I32 | I64 | F32 | F64 | V128 | FuncRef | ExternRef
|
||||
|
||||
let to_int = function
|
||||
| I32 -> 0
|
||||
| I64 -> 1
|
||||
| F32 -> 2
|
||||
| F64 -> 3
|
||||
| FuncRef -> 4
|
||||
| ExternRef -> 5
|
||||
| V128 -> 4
|
||||
| FuncRef -> 5
|
||||
| ExternRef -> 6
|
||||
|
||||
let of_int = function
|
||||
| 0 -> I32
|
||||
| 1 -> I64
|
||||
| 2 -> F32
|
||||
| 3 -> F64
|
||||
| 4 -> FuncRef
|
||||
| 5 -> ExternRef
|
||||
| 4 -> V128
|
||||
| 5 -> FuncRef
|
||||
| 6 -> ExternRef
|
||||
| n -> invalid_arg ("Extism_val_type.of_int: " ^ string_of_int n)
|
||||
|
||||
let t : t typ = view ~read:of_int ~write:to_int int
|
||||
|
||||
@@ -16,7 +16,14 @@ end
|
||||
|
||||
(** [Val_type] enumerates every possible argument/result type *)
|
||||
module Val_type : sig
|
||||
type t = I32 | I64 | F32 | F64 | FuncRef | ExternRef (** Value type *)
|
||||
type t =
|
||||
| I32
|
||||
| I64
|
||||
| F32
|
||||
| F64
|
||||
| V128
|
||||
| FuncRef
|
||||
| ExternRef (** Value type *)
|
||||
|
||||
val of_int : int -> t
|
||||
val to_int : t -> int
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
(library
|
||||
(name extism_manifest)
|
||||
(public_name extism-manifest)
|
||||
(inline_tests)
|
||||
(libraries base64)
|
||||
(preprocess
|
||||
(pps ppx_yojson_conv)))
|
||||
(pps ppx_yojson_conv ppx_inline_test)))
|
||||
|
||||
@@ -96,3 +96,16 @@ let of_file filename =
|
||||
t_of_yojson j
|
||||
|
||||
let with_config t config = { t with config = Some config }
|
||||
|
||||
let%test "rountrip" =
|
||||
let config = [ ("a", Some "b"); ("b", Some "c") ] in
|
||||
let memory = { max_pages = Some 5 } in
|
||||
let t =
|
||||
create ~config ~memory ~allowed_hosts:[ "example.com" ]
|
||||
~allowed_paths:[ ("a", "b") ]
|
||||
~timeout_ms:1000 []
|
||||
in
|
||||
let a = to_json t in
|
||||
let b = of_json a in
|
||||
let c = to_json b in
|
||||
String.equal a c
|
||||
|
||||
@@ -7,4 +7,5 @@ from .extism import (
|
||||
host_fn,
|
||||
Function,
|
||||
ValType,
|
||||
Val,
|
||||
)
|
||||
|
||||
@@ -217,6 +217,8 @@ class Function:
|
||||
)
|
||||
|
||||
def __del__(self):
|
||||
if not hasattr(self, "pointer"):
|
||||
return
|
||||
if self.pointer is not None:
|
||||
_lib.extism_function_free(self.pointer)
|
||||
|
||||
@@ -413,8 +415,9 @@ class ValType(Enum):
|
||||
I64 = 1
|
||||
F32 = 2
|
||||
F64 = 3
|
||||
FUNC_REF = 4
|
||||
EXTERN_REF = 5
|
||||
V128 = 4
|
||||
FUNC_REF = 5
|
||||
EXTERN_REF = 6
|
||||
|
||||
|
||||
class Val:
|
||||
|
||||
Binary file not shown.
@@ -76,8 +76,30 @@ class TestExtism(unittest.TestCase):
|
||||
"plugin timeout exceeded 1000ms expectation",
|
||||
)
|
||||
|
||||
def _manifest(self):
|
||||
wasm = self._count_vowels_wasm()
|
||||
def test_extism_host_function(self):
|
||||
@extism.host_fn
|
||||
def hello_world(plugin, params, results, user_data):
|
||||
offs = plugin.alloc(len(user_data))
|
||||
mem = plugin.memory(offs)
|
||||
mem[:] = user_data
|
||||
results[0].value = offs.offset
|
||||
|
||||
with extism.Context() as ctx:
|
||||
f = [
|
||||
extism.Function(
|
||||
"hello_world",
|
||||
[extism.ValType.I64],
|
||||
[extism.ValType.I64],
|
||||
hello_world,
|
||||
b"test",
|
||||
)
|
||||
]
|
||||
plugin = ctx.plugin(self._manifest(functions=True), functions=f, wasi=True)
|
||||
res = plugin.call("count_vowels", "aaa")
|
||||
self.assertEqual(res, b"test")
|
||||
|
||||
def _manifest(self, functions=False):
|
||||
wasm = self._count_vowels_wasm(functions)
|
||||
hash = hashlib.sha256(wasm).hexdigest()
|
||||
return {"wasm": [{"data": wasm, "hash": hash}], "memory": {"max_pages": 5}}
|
||||
|
||||
@@ -90,14 +112,14 @@ class TestExtism(unittest.TestCase):
|
||||
"timeout_ms": 1000,
|
||||
}
|
||||
|
||||
def _count_vowels_wasm(self):
|
||||
return read_test_wasm("code.wasm")
|
||||
def _count_vowels_wasm(self, functions=False):
|
||||
return read_test_wasm("code.wasm" if not functions else "code-functions.wasm")
|
||||
|
||||
def _infinite_loop_wasm(self):
|
||||
return read_test_wasm("loop.wasm")
|
||||
|
||||
|
||||
def read_test_wasm(p):
|
||||
path = join(dirname(__file__), p)
|
||||
path = join(dirname(__file__), "..", "..", "wasm", p)
|
||||
with open(path, "rb") as wasm_file:
|
||||
return wasm_file.read()
|
||||
|
||||
Binary file not shown.
@@ -83,7 +83,7 @@ class TestExtism < Minitest::Test
|
||||
{
|
||||
wasm: [
|
||||
{
|
||||
path: File.join(__dir__, "code.wasm"),
|
||||
path: File.join(__dir__, "../../wasm/code.wasm"),
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
fn main() {
|
||||
let fn_macro = "
|
||||
#define EXTISM_FUNCTION(N) extern void N(ExtismCurrentPlugin*, const ExtismVal*, ExtismSize, ExtismVal*, ExtismSize, void*)
|
||||
#define EXTISM_GO_FUNCTION(N) extern void N(ExtismCurrentPlugin*, ExtismVal*, ExtismSize, ExtismVal*, ExtismSize, uintptr_t)
|
||||
#define EXTISM_GO_FUNCTION(N) extern void N(void*, ExtismVal*, ExtismSize, ExtismVal*, ExtismSize, uintptr_t)
|
||||
";
|
||||
if let Ok(bindings) = cbindgen::Builder::new()
|
||||
.with_crate(".")
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
#define EXTISM_FUNCTION(N) extern void N(ExtismCurrentPlugin*, const ExtismVal*, ExtismSize, ExtismVal*, ExtismSize, void*)
|
||||
#define EXTISM_GO_FUNCTION(N) extern void N(ExtismCurrentPlugin*, ExtismVal*, ExtismSize, ExtismVal*, ExtismSize, uintptr_t)
|
||||
#define EXTISM_GO_FUNCTION(N) extern void N(void*, ExtismVal*, ExtismSize, ExtismVal*, ExtismSize, uintptr_t)
|
||||
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user