495 lines
12 KiB
Go
495 lines
12 KiB
Go
package gojs_test
|
|
|
|
import (
|
|
"apigo.cc/apigo/gojs"
|
|
"apigo.cc/apigo/gojs/dop251/goja"
|
|
_ "apigo.cc/apigo/gojs/modules"
|
|
"fmt"
|
|
"github.com/ssgo/u"
|
|
"runtime"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
type Object struct {
|
|
id string
|
|
//plus func(int, int) int
|
|
plus goja.Callable
|
|
baseNumber int
|
|
}
|
|
|
|
//type PlusConfig struct {
|
|
// BaseNumber int
|
|
// //Action func(int, int) int
|
|
// Action goja.Callable
|
|
//}
|
|
|
|
func (obj *Object) GetId(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
|
return vm.ToValue(obj.id)
|
|
}
|
|
|
|
// func (obj *Object) SetPlusFuncAndRun(cb func(int, int) int) int {
|
|
func (obj *Object) SetPlusFuncAndRun(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
|
args := gojs.MakeArgs(&argsIn, vm).Check(1)
|
|
obj.plus = args.Func(0)
|
|
r, err := obj.plus(args.This, vm.ToValue(1), vm.ToValue(2))
|
|
if err != nil {
|
|
panic(vm.NewGoError(err))
|
|
}
|
|
return r
|
|
}
|
|
|
|
// func (obj *Object) SetPlusFunc(cb func(int, int) int) {
|
|
func (obj *Object) SetPlusFunc(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
|
//obj.plus = cb
|
|
args := gojs.MakeArgs(&argsIn, vm).Check(1)
|
|
obj.plus = args.Func(0)
|
|
return nil
|
|
}
|
|
|
|
// func (obj *Object) SetPlusFunc2(conf PlusConfig) {
|
|
func (obj *Object) SetPlusFunc2(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
|
//obj.baseNumber = conf.BaseNumber
|
|
//obj.plus = conf.Action
|
|
args := gojs.MakeArgs(&argsIn, vm).Check(1)
|
|
o := args.Obj(0)
|
|
baseNumber := o.Get("baseNumber")
|
|
if baseNumber != nil {
|
|
obj.baseNumber = int(baseNumber.ToInteger())
|
|
}
|
|
action := o.Get("action")
|
|
if action != nil {
|
|
obj.plus = gojs.GetFunc(action)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// func (obj *Object) Plus(a ...int) int {
|
|
func (obj *Object) Plus(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
|
args := gojs.MakeArgs(&argsIn, vm).Check(2)
|
|
r, err := obj.plus(args.This, args.Arguments[0], args.Arguments[1])
|
|
if err != nil {
|
|
panic(vm.NewGoError(err))
|
|
}
|
|
return r
|
|
}
|
|
|
|
// func (obj *Object) PlusX(a int, b int) int {
|
|
func (obj *Object) PlusX(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
|
args := gojs.MakeArgs(&argsIn, vm).Check(2)
|
|
//return obj.plus(a, b) + obj.baseNumber
|
|
r, err := obj.plus(args.This, args.Arguments[0], args.Arguments[1])
|
|
if err != nil {
|
|
panic(vm.NewGoError(err))
|
|
}
|
|
return vm.ToValue(r.ToInteger() + int64(obj.baseNumber))
|
|
}
|
|
|
|
// func (obj *Object) AsyncPlus(a int, b int) int {
|
|
func (obj *Object) AsyncPlus(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
|
args := gojs.MakeArgs(&argsIn, vm).Check(2)
|
|
//ch := make(chan bool, 1)
|
|
//r := 0
|
|
//go func() {
|
|
// time.Sleep(300 * time.Millisecond)
|
|
// r = obj.plus(a, b)
|
|
// ch <- true
|
|
//}()
|
|
//<-ch
|
|
//return r
|
|
ch := make(chan bool, 1)
|
|
var r goja.Value
|
|
var err error
|
|
go func() {
|
|
time.Sleep(300 * time.Millisecond)
|
|
//r = obj.plus(a, b)
|
|
r, err = obj.plus(args.This, args.Arguments[0], args.Arguments[1])
|
|
ch <- true
|
|
}()
|
|
<-ch
|
|
if err != nil {
|
|
panic(vm.NewGoError(err))
|
|
}
|
|
return r
|
|
}
|
|
|
|
type TestBirthday struct {
|
|
Year int
|
|
Month int
|
|
Day int
|
|
}
|
|
|
|
type TestBaseUser struct {
|
|
Id int
|
|
Name string
|
|
}
|
|
|
|
type TestUser struct {
|
|
TestBaseUser
|
|
Birthday *TestBirthday
|
|
}
|
|
|
|
// func (b *TestBirthday) String() string {
|
|
func (b *TestBirthday) String(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
|
//return fmt.Sprintln(b.Year, b.Month, b.Day)
|
|
return vm.ToValue(fmt.Sprintln(b.Year, b.Month, b.Day))
|
|
}
|
|
|
|
// func (u *TestUser) GetBirthdayString() string {
|
|
func (u *TestUser) GetBirthdayString(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
|
//return u.Birthday.String()
|
|
return vm.ToValue(fmt.Sprintln(u.Birthday.Year, u.Birthday.Month, u.Birthday.Day))
|
|
}
|
|
|
|
func init() {
|
|
defaultObject := Object{id: "o-00"}
|
|
gojs.Register("aaa/obj", gojs.Module{
|
|
Object: map[string]interface{}{
|
|
"name": "1233",
|
|
"list1": []interface{}{1, "2", map[string]interface{}{"aaa": 111, "bbb": "222"}, true},
|
|
//"log": log.DefaultLogger.Info,
|
|
"log1": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
|
args := gojs.MakeArgs(&argsIn, vm).Check(1)
|
|
args.Logger.Info(args.Str(0), args.Map2Arr(1)...)
|
|
return nil
|
|
},
|
|
//"getId": defaultObject.GetId,
|
|
"getId": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
|
return vm.ToValue(defaultObject.id)
|
|
},
|
|
"new": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
|
args := gojs.MakeArgs(&argsIn, vm).Check(1)
|
|
return vm.ToValue(Object{id: args.Str(0)})
|
|
},
|
|
//"new": func(id string) interface{} {
|
|
// return &Object{id: id}
|
|
//},
|
|
"test1": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
|
//args := gojs.MakeArgs(&argsIn, VM).Check(3)
|
|
return nil
|
|
},
|
|
//"test1": func(id int, id2 uint16, id3 float64) *TestUser {
|
|
// return nil
|
|
//},
|
|
"echo": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
|
args := gojs.MakeArgs(&argsIn, vm).Check(2)
|
|
r, err := args.Func(1)(args.This, args.Arguments[0], vm.ToValue(1))
|
|
if err != nil {
|
|
panic(vm.NewGoError(err))
|
|
}
|
|
return r
|
|
},
|
|
//"echo": func(text string, echoFunc func(text string, t2 int) string, t3 []uint32, t4 *bool) interface{} {
|
|
// return echoFunc(text, 0)
|
|
//},
|
|
"echoTimes": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
|
args := gojs.MakeArgs(&argsIn, vm).Check(1)
|
|
echoFunc := args.Func(0)
|
|
for i := 0; i < 5; i++ {
|
|
//time.Sleep(100 * time.Millisecond)
|
|
_, err := echoFunc(args.This, vm.ToValue(fmt.Sprint(i)))
|
|
if err != nil {
|
|
panic(vm.NewGoError(err))
|
|
}
|
|
}
|
|
return nil
|
|
},
|
|
//"echoTimes": func(echoFunc func(text string)) {
|
|
// for i := 0; i < 5; i++ {
|
|
// //time.Sleep(100 * time.Millisecond)
|
|
// echoFunc(fmt.Sprint(i))
|
|
// }
|
|
//},
|
|
},
|
|
TsCode: "",
|
|
Example: "",
|
|
})
|
|
//plg := plugin.Plugin{
|
|
// Id: "obj",
|
|
// Name: "test obj plugin",
|
|
// Objects: map[string]interface{}{
|
|
// "name": "1233",
|
|
// "list1": []interface{}{1, "2", map[string]interface{}{"aaa": 111, "bbb": "222"}, true},
|
|
// "log1": log.DefaultLogger.Info,
|
|
// "getId": defaultObject.GetId,
|
|
// "new": func(id string) interface{} {
|
|
// return &Object{id: id}
|
|
// },
|
|
// "test1": func(id int, id2 uint16, id3 float64) *TestUser {
|
|
// return nil
|
|
// },
|
|
// "echo": func(text string, echoFunc func(text string, t2 int) string, t3 []uint32, t4 *bool) interface{} {
|
|
// return echoFunc(text, 0)
|
|
// },
|
|
// "echoTimes": func(echoFunc func(text string)) {
|
|
// for i := 0; i < 5; i++ {
|
|
// //time.Sleep(100 * time.Millisecond)
|
|
// echoFunc(fmt.Sprint(i))
|
|
// }
|
|
// },
|
|
// },
|
|
//}
|
|
//plugin.Register(plg)
|
|
//gojs.SetPluginsConfig(map[string]plugin.Config{
|
|
// "obj": plugin.Config{},
|
|
//})
|
|
}
|
|
|
|
func test(t *testing.T, name string, check bool, extArgs ...interface{}) {
|
|
if check {
|
|
fmt.Println(u.Green(name), u.BGreen("[OK]"))
|
|
} else {
|
|
fmt.Println(u.Red(name), u.BRed("[Failed]"), fmt.Sprintln(extArgs...))
|
|
t.Fatal(name)
|
|
}
|
|
}
|
|
|
|
//func TestTS(t *testing.T) {
|
|
// plg := plugin.Get("obj")
|
|
// exportCode, _ := gojs.MakePluginCode(plg)
|
|
// test(t, "ts code", strings.Contains(exportCode, "(echoFunc: (text: string) => void)"), exportCode)
|
|
//}
|
|
|
|
func TestGlobal(t *testing.T) {
|
|
code := `
|
|
import lg from 'log'
|
|
import console from 'console'
|
|
log1('test', 'name', 'log')
|
|
lg.info('test', {name:'log'})
|
|
console.info('test', {name:'log'})
|
|
return plus(number,2)
|
|
`
|
|
globals := map[string]interface{}{
|
|
"number": 9,
|
|
//"log1": log.DefaultLogger.Info,
|
|
"log1": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
|
args := gojs.MakeArgs(&argsIn, vm).Check(1)
|
|
args.Logger.Info(args.Str(0), args.Map2Arr(1)...)
|
|
return nil
|
|
},
|
|
//"plus": func(i, j int) int { return i + j },
|
|
"plus": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
|
args := gojs.MakeArgs(&argsIn, vm).Check(2)
|
|
return vm.ToValue(args.Int(0) + args.Int(1))
|
|
},
|
|
}
|
|
|
|
//r, _ := gojs.Run(code, &gojs.RuntimeOption{
|
|
// Globals: globals,
|
|
//})
|
|
rt := gojs.New()
|
|
_ = rt.SetGlobal(globals)
|
|
err := rt.StartFromCode(code, "test.js")
|
|
if err != nil {
|
|
t.Fatal(err.Error())
|
|
}
|
|
r, err := rt.RunMain()
|
|
if err != nil {
|
|
t.Fatal(err.Error())
|
|
}
|
|
test(t, "call", u.Int(r) == 11, r)
|
|
}
|
|
|
|
func TestPlugin(t *testing.T) {
|
|
rt := gojs.New()
|
|
_, _ = rt.RunCode("import obj from 'aaa/obj'")
|
|
r, err := rt.RunCode("obj.getId()")
|
|
test(t, "obj.getId()", u.String(r) == "o-00", r, err)
|
|
|
|
r, err = rt.RunCode(`
|
|
let o = obj.new('o-01')
|
|
o.GetId()
|
|
`)
|
|
test(t, "new obj.getId()", u.String(r) == "o-01", r, err)
|
|
|
|
t1 := time.Now()
|
|
r, err = rt.RunCode(`
|
|
out = ''
|
|
obj.echo('123', function(text){
|
|
out = text
|
|
}, null)
|
|
out
|
|
`)
|
|
t2 := time.Now()
|
|
fmt.Println("time:", t2.UnixMicro()-t1.UnixMicro())
|
|
test(t, "callback", u.String(r) == "123", r, err)
|
|
|
|
t1 = time.Now()
|
|
r, err = rt.RunCode(`
|
|
out = ''
|
|
obj.echoTimes(function(text){
|
|
out += text
|
|
})
|
|
out
|
|
`)
|
|
t2 = time.Now()
|
|
fmt.Println("time:", t2.UnixMicro()-t1.UnixMicro())
|
|
test(t, "callbacks", u.String(r) == "01234", r, err)
|
|
}
|
|
|
|
func TestCallback(t *testing.T) {
|
|
r, err := gojs.Run(`
|
|
import obj from 'aaa/obj'
|
|
o = obj.new('cb')
|
|
return o.SetPlusFuncAndRun(function (a, b){
|
|
return a+b
|
|
})
|
|
`, "")
|
|
test(t, "plus with callback1", u.String(r) == "3", r, err)
|
|
|
|
r, err = gojs.Run(`
|
|
import obj from 'aaa/obj'
|
|
o = obj.new('cb')
|
|
o.SetPlusFunc(function(a, b){
|
|
return a+b
|
|
})
|
|
return o.Plus(1, 2)
|
|
`, "")
|
|
test(t, "plus with callback2.1", u.String(r) == "3", r, err)
|
|
|
|
r, err = gojs.Run(`
|
|
import obj from 'aaa/obj'
|
|
o = obj.new('cb')
|
|
function plus(a, b){
|
|
return a+b
|
|
}
|
|
o.SetPlusFunc(plus)
|
|
return o.Plus(1, 2)
|
|
`, "")
|
|
test(t, "plus with callback2.2", u.String(r) == "3", r, err)
|
|
|
|
r, err = gojs.Run(`
|
|
import obj from 'aaa/obj'
|
|
o = obj.new('cb')
|
|
o.SetPlusFunc2({action: function(a, b){
|
|
return a+b
|
|
}})
|
|
return o.Plus(1, 2)
|
|
`, "")
|
|
test(t, "plus with callback3.1", u.String(r) == "3", r, err)
|
|
|
|
r, err = gojs.Run(`
|
|
import obj from 'aaa/obj'
|
|
o = obj.new('cb')
|
|
function plus(a, b){
|
|
return a+b
|
|
}
|
|
o.SetPlusFunc2({baseNumber:10, action: plus})
|
|
return o.PlusX(1, 2)
|
|
`, "")
|
|
test(t, "plus with callback3.2", u.String(r) == "13", r, err)
|
|
|
|
rt := gojs.New()
|
|
rt.RunCode(`
|
|
import obj from 'aaa/obj'
|
|
o = obj.new('cb')
|
|
`)
|
|
rt.RunCode(`
|
|
o.SetPlusFunc2({action: function(a, b){
|
|
return a+b
|
|
}})
|
|
`)
|
|
r, err = rt.RunCode(`
|
|
o.Plus(1, 2)
|
|
`)
|
|
test(t, "plus with callback4.1", u.String(r) == "3", r, err)
|
|
|
|
r, err = rt.RunCode(`
|
|
o.AsyncPlus(1, 2)
|
|
`)
|
|
// unexpected, maybe get exception in other go coroutine
|
|
test(t, "plus with callback4.2", u.String(r) == "3" || u.String(r) == "0", r, err)
|
|
}
|
|
|
|
//func TestInnerModule(t *testing.T) {
|
|
// rt := gojs.New()
|
|
// rt.RunCode(`
|
|
// import {loadFile} from "std"
|
|
// import * as os from "os"
|
|
// import console from 'console'
|
|
// globalThis.goMod = loadFile('go.mod')
|
|
// globalThis.platform = os.platform
|
|
//`)
|
|
// goModStr, _ := rt.RunCode(`
|
|
// goMod
|
|
// `)
|
|
// platformStr, _ := rt.RunCode(`
|
|
// platform
|
|
// `)
|
|
// test(t, "check std.loadFile", strings.Contains(u.String(goModStr), "apigo"), goModStr)
|
|
// test(t, "check os.platform", u.String(platformStr) != "", platformStr)
|
|
//}
|
|
|
|
func TestAsync(t *testing.T) {
|
|
rt := gojs.New()
|
|
_, err := rt.RunCode(`
|
|
import console from 'console'
|
|
let t1 = new Date().getTime()
|
|
new Promise(resolve => {
|
|
setTimeout(resolve, 200)
|
|
}).then(()=>{
|
|
globalThis.promiseValue = new Date().getTime() - t1
|
|
})
|
|
setTimeout(()=>{
|
|
globalThis.timeoutValue = new Date().getTime() - t1
|
|
}, 300)
|
|
`)
|
|
time.Sleep(310 * time.Millisecond)
|
|
timeoutValue, err := rt.RunCode(`
|
|
timeoutValue
|
|
`)
|
|
test(t, "check timeoutValue", u.Int(timeoutValue) >= 300 && u.Int(timeoutValue) <= 400, timeoutValue, err)
|
|
promiseValue, err := rt.RunCode(`
|
|
promiseValue
|
|
`)
|
|
test(t, "check promiseValue", u.Int(promiseValue) >= 200 && u.Int(promiseValue) <= 300, promiseValue, err)
|
|
}
|
|
|
|
func BenchmarkEcho(tb *testing.B) {
|
|
tb.StopTimer()
|
|
ms1 := runtime.MemStats{}
|
|
runtime.ReadMemStats(&ms1)
|
|
tb.StartTimer()
|
|
for i := 0; i < tb.N; i++ {
|
|
gojs.Run(`return 1`, "")
|
|
}
|
|
tb.StopTimer()
|
|
|
|
ms2 := runtime.MemStats{}
|
|
runtime.ReadMemStats(&ms2)
|
|
|
|
runtime.GC()
|
|
ms3 := runtime.MemStats{}
|
|
runtime.ReadMemStats(&ms3)
|
|
fmt.Println(">>", ms1.HeapInuse, ms2.HeapInuse, ms3.HeapInuse)
|
|
}
|
|
|
|
func BenchmarkCallback(tb *testing.B) {
|
|
tb.StopTimer()
|
|
ms1 := runtime.MemStats{}
|
|
runtime.ReadMemStats(&ms1)
|
|
tb.StartTimer()
|
|
for i := 0; i < tb.N; i++ {
|
|
gojs.Run(`
|
|
import obj from 'aaa/obj'
|
|
out = ''
|
|
obj.echoTimes(function(text){
|
|
out += text
|
|
})
|
|
`, "")
|
|
}
|
|
tb.StopTimer()
|
|
|
|
ms2 := runtime.MemStats{}
|
|
runtime.ReadMemStats(&ms2)
|
|
|
|
runtime.GC()
|
|
ms3 := runtime.MemStats{}
|
|
runtime.ReadMemStats(&ms3)
|
|
fmt.Println(">>", ms1.HeapInuse, ms2.HeapInuse, ms3.HeapInuse)
|
|
}
|
|
|
|
//func TestExport(t *testing.T) {
|
|
// fmt.Println(u.BCyan(gojs.ExportForDev()))
|
|
//}
|