pre migrate
This commit is contained in:
@@ -6,8 +6,6 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"modernc.org/quickjs"
|
||||
)
|
||||
|
||||
type TestArgs struct {
|
||||
@@ -19,77 +17,17 @@ func (t TestArgs) Validate() error {
|
||||
}
|
||||
|
||||
func TestAsyncFunction(t *testing.T) {
|
||||
registryMutex.RLock()
|
||||
defer registryMutex.RUnlock()
|
||||
|
||||
RegisterAsyncFunction("testAsync", func(_ context.Context, args TestArgs) (string, error) {
|
||||
return "result: " + args.Field1, nil
|
||||
})
|
||||
|
||||
registryMutex.RLock()
|
||||
fn, ok := functionRegistry["testAsync"]
|
||||
registryMutex.RUnlock()
|
||||
|
||||
require.True(t, ok, "testAsync should be registered")
|
||||
assert.Contains(t, fn.Definition(), "Promise<string>", "definition should include Promise<string>")
|
||||
}
|
||||
|
||||
func TestAsyncFunctionResolution(t *testing.T) {
|
||||
RegisterAsyncFunction("resolveTest", func(_ context.Context, args TestArgs) (string, error) {
|
||||
return "test-result", nil
|
||||
})
|
||||
|
||||
vm, err := quickjs.NewVM()
|
||||
require.NoError(t, err)
|
||||
defer func() {
|
||||
_ = vm.Close()
|
||||
}()
|
||||
vm.SetCanBlock(true)
|
||||
|
||||
RegisterFunctions(context.Background(), vm)
|
||||
|
||||
result, err := vm.Eval(`resolveTest("hello")`, quickjs.EvalGlobal)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, result)
|
||||
}
|
||||
|
||||
func TestAsyncFunctionRejection(t *testing.T) {
|
||||
RegisterAsyncFunction("rejectTest", func(_ context.Context, args TestArgs) (string, error) {
|
||||
return "", assert.AnError
|
||||
})
|
||||
|
||||
vm, err := quickjs.NewVM()
|
||||
require.NoError(t, err)
|
||||
defer func() {
|
||||
_ = vm.Close()
|
||||
}()
|
||||
vm.SetCanBlock(true)
|
||||
|
||||
RegisterFunctions(context.Background(), vm)
|
||||
|
||||
result, err := vm.Eval(`rejectTest({field1: "hello"})`, quickjs.EvalGlobal)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, result)
|
||||
}
|
||||
|
||||
func TestNonPromise(t *testing.T) {
|
||||
RegisterFunction("nonPromiseTest", func(_ context.Context, args TestArgs) (string, error) {
|
||||
return "sync-result", nil
|
||||
})
|
||||
|
||||
vm, err := quickjs.NewVM()
|
||||
require.NoError(t, err)
|
||||
defer func() {
|
||||
_ = vm.Close()
|
||||
}()
|
||||
vm.SetCanBlock(true)
|
||||
|
||||
RegisterFunctions(context.Background(), vm)
|
||||
|
||||
result, err := vm.Eval(`nonPromiseTest({field1: "hello"})`, quickjs.EvalGlobal)
|
||||
require.NoError(t, err)
|
||||
|
||||
if obj, ok := result.(*quickjs.Object); ok {
|
||||
var arr []any
|
||||
if err := obj.Into(&arr); err == nil && len(arr) > 0 {
|
||||
assert.Equal(t, "sync-result", arr[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
// TOOD: Test Normal Function
|
||||
|
||||
@@ -13,7 +13,7 @@ var (
|
||||
collector *typeCollector
|
||||
)
|
||||
|
||||
func registerFunction[A Args, R any](name string, isAsync bool, fn RawFunc[A, R]) {
|
||||
func registerFunction[A Args, R any](name string, isAsync bool, fn GoFunc[A, R]) {
|
||||
registryMutex.Lock()
|
||||
defer registryMutex.Unlock()
|
||||
|
||||
@@ -35,6 +35,7 @@ func registerFunction[A Args, R any](name string, isAsync bool, fn RawFunc[A, R]
|
||||
fn: fn,
|
||||
types: types,
|
||||
definition: generateTypeScriptDefinition(name, tType, fnType, isAsync, paramTypes),
|
||||
isAsync: isAsync,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,10 +70,10 @@ func GetRegisteredFunctions() map[string]Function {
|
||||
return functionRegistry
|
||||
}
|
||||
|
||||
func RegisterFunction[T Args, R any](name string, fn RawFunc[T, R]) {
|
||||
func RegisterFunction[T Args, R any](name string, fn GoFunc[T, R]) {
|
||||
registerFunction(name, false, fn)
|
||||
}
|
||||
|
||||
func RegisterAsyncFunction[T Args, R any](name string, fn RawFunc[T, R]) {
|
||||
func RegisterAsyncFunction[T Args, R any](name string, fn GoFunc[T, R]) {
|
||||
registerFunction(name, true, fn)
|
||||
}
|
||||
|
||||
@@ -10,10 +10,11 @@ type Function interface {
|
||||
Name() string
|
||||
Types() []string
|
||||
Definition() string
|
||||
WrapFn(context.Context) func(...any) (any, error)
|
||||
IsAsync() bool
|
||||
Call(context.Context, []any) (any, error)
|
||||
}
|
||||
|
||||
type RawFunc[A Args, R any] func(context.Context, A) (R, error)
|
||||
type GoFunc[A Args, R any] func(context.Context, A) (R, error)
|
||||
|
||||
type Args interface {
|
||||
Validate() error
|
||||
@@ -21,9 +22,10 @@ type Args interface {
|
||||
|
||||
type functionImpl[A Args, R any] struct {
|
||||
name string
|
||||
fn RawFunc[A, R]
|
||||
fn GoFunc[A, R]
|
||||
definition string
|
||||
types []string
|
||||
isAsync bool
|
||||
}
|
||||
|
||||
func (b *functionImpl[A, R]) Name() string {
|
||||
@@ -38,39 +40,38 @@ func (b *functionImpl[A, R]) Definition() string {
|
||||
return b.definition
|
||||
}
|
||||
|
||||
func (b *functionImpl[A, R]) WrapFn(ctx context.Context) func(...any) (any, error) {
|
||||
return func(allArgs ...any) (any, error) {
|
||||
// Populate Arguments
|
||||
var fnArgs A
|
||||
aVal := reflect.ValueOf(&fnArgs).Elem()
|
||||
|
||||
// Populate Fields
|
||||
for i := range min(aVal.NumField(), len(allArgs)) {
|
||||
field := aVal.Field(i)
|
||||
|
||||
if !field.CanSet() {
|
||||
return nil, errors.New("cannot set field")
|
||||
}
|
||||
|
||||
argVal := reflect.ValueOf(allArgs[i])
|
||||
if !argVal.Type().AssignableTo(field.Type()) {
|
||||
return nil, errors.New("cannot assign field")
|
||||
}
|
||||
|
||||
field.Set(argVal)
|
||||
}
|
||||
|
||||
// Validate
|
||||
if err := fnArgs.Validate(); err != nil {
|
||||
return nil, errors.New("cannot validate args")
|
||||
}
|
||||
|
||||
// Call Function
|
||||
resp, err := b.fn(ctx, fnArgs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
func (b *functionImpl[A, R]) IsAsync() bool {
|
||||
return b.isAsync
|
||||
}
|
||||
|
||||
func (b *functionImpl[A, R]) Function() any {
|
||||
return b.fn
|
||||
}
|
||||
|
||||
func (b *functionImpl[A, R]) Call(ctx context.Context, allArgs []any) (any, error) {
|
||||
return b.CallGeneric(ctx, allArgs)
|
||||
}
|
||||
|
||||
func (b *functionImpl[A, R]) CallGeneric(ctx context.Context, allArgs []any) (zeroR R, err error) {
|
||||
// Populate Arguments
|
||||
var fnArgs A
|
||||
aVal := reflect.ValueOf(&fnArgs).Elem()
|
||||
|
||||
// Populate Fields
|
||||
for i := range min(aVal.NumField(), len(allArgs)) {
|
||||
field := aVal.Field(i)
|
||||
|
||||
if !field.CanSet() {
|
||||
return zeroR, errors.New("cannot set field")
|
||||
}
|
||||
|
||||
argVal := reflect.ValueOf(allArgs[i])
|
||||
if !argVal.Type().AssignableTo(field.Type()) {
|
||||
return zeroR, errors.New("cannot assign field")
|
||||
}
|
||||
|
||||
field.Set(argVal)
|
||||
}
|
||||
|
||||
return b.fn(ctx, fnArgs)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user