gojs/gojs_test.go

357 lines
7.3 KiB
Go

package gojs_test
import (
"apigo.cc/apigo/gojs"
"apigo.cc/apigo/plugin"
"fmt"
"github.com/ssgo/log"
"github.com/ssgo/u"
"runtime"
"strings"
"testing"
"time"
)
type Object struct {
id string
plus func(int, int) int
baseNumber int
}
type PlusConfig struct {
BaseNumber int
Action func(int, int) int
}
func (obj *Object) GetId() string {
return obj.id
}
func (obj *Object) SetPlusFuncAndRun(cb func(int, int) int) int {
obj.plus = cb
return obj.plus(1, 2)
}
func (obj *Object) SetPlusFunc(cb func(int, int) int) {
obj.plus = cb
}
func (obj *Object) SetPlusFunc2(conf PlusConfig) {
obj.baseNumber = conf.BaseNumber
obj.plus = conf.Action
}
func (obj *Object) Plus(a ...int) int {
return obj.plus(a[0], a[1])
}
func (obj *Object) PlusX(a int, b int) int {
return obj.plus(a, b) + obj.baseNumber
}
func (obj *Object) AsyncPlus(a int, b int) int {
ch := make(chan bool, 1)
r := 0
go func() {
time.Sleep(300 * time.Millisecond)
r = obj.plus(a, b)
ch <- true
}()
<-ch
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 {
return fmt.Sprintln(b.Year, b.Month, b.Day)
}
func (u *TestUser) GetBirthdayString() string {
return u.Birthday.String()
}
func init() {
defaultObject := Object{id: "o-00"}
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},
"log": 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.Error(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 'logger'
import console from 'console'
log('test', 'name', 'log')
lg.info('test', {name:'log'})
console.info('test', {name:'log'})
return plus(number,2)
`
globals := map[string]interface{}{
"number": 9,
"log": log.DefaultLogger.Info,
"plus": func(i, j int) int { return i + j },
}
r, _ := gojs.Run(code, &gojs.RuntimeOption{
Globals: globals,
})
test(t, "call", u.Int(r) == 11, r)
}
func TestPlugin(t *testing.T) {
rt := gojs.New(nil)
rt.Exec("import obj from 'obj'")
r, _ := rt.Run("return obj.getId()")
test(t, "obj.getId()", u.String(r) == "o-00", r)
r, _ = rt.Run(`
o = obj.new('o-01')
return o.getId()
`)
test(t, "new obj.getId()", u.String(r) == "o-01", r)
t1 := time.Now()
r, _ = rt.Run(`
out = ''
obj.echo('123', function(text){
out = text
}, null)
return out
`)
t2 := time.Now()
fmt.Println("time:", t2.UnixMicro()-t1.UnixMicro())
test(t, "callback", u.String(r) == "123", r)
t1 = time.Now()
r, _ = rt.Run(`
out = ''
obj.echoTimes(function(text){
out += text
})
return out
`)
t2 = time.Now()
fmt.Println("time:", t2.UnixMicro()-t1.UnixMicro())
test(t, "callbacks", u.String(r) == "01234", r)
}
func TestCallback(t *testing.T) {
r, _ := gojs.Run(`
import obj from 'obj'
o = obj.new('cb')
return o.setPlusFuncAndRun(function (a, b){
return a+b
})
`, nil)
test(t, "plus with callback1", u.String(r) == "3", r)
r, _ = gojs.Run(`
import obj from 'obj'
o = obj.new('cb')
o.setPlusFunc(function(a, b){
return a+b
})
return o.plus(1, 2)
`, nil)
test(t, "plus with callback2.1", u.String(r) == "3", r)
r, _ = gojs.Run(`
import obj from 'obj'
o = obj.new('cb')
function plus(a, b){
return a+b
}
o.setPlusFunc(plus)
return o.plus(1, 2)
`, nil)
test(t, "plus with callback2.2", u.String(r) == "3", r)
r, _ = gojs.Run(`
import obj from 'obj'
o = obj.new('cb')
o.setPlusFunc2({action: function(a, b){
return a+b
}})
return o.plus(1, 2)
`, nil)
test(t, "plus with callback3.1", u.String(r) == "3", r)
r, _ = gojs.Run(`
import obj from 'obj'
o = obj.new('cb')
function plus(a, b){
return a+b
}
o.setPlusFunc2({baseNumber:10, action: plus})
return o.plusX(1, 2)
`, nil)
test(t, "plus with callback3.2", u.String(r) == "13", r)
rt := gojs.New(nil)
rt.Exec(`
import obj from 'obj'
o = obj.new('cb')
`)
rt.Run(`
o.setPlusFunc2({action: function(a, b){
return a+b
}})
`)
r, _ = rt.Run(`
return o.plus(1, 2)
`)
test(t, "plus with callback4.1", u.String(r) == "3", r)
r, _ = rt.Run(`
return 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)
rt.Close()
}
func TestInnerModule(t *testing.T) {
rt := gojs.New(nil)
rt.Exec(`
import {loadFile} from "std"
import * as os from "os"
import console from 'console'
globalThis.goMod = loadFile('go.mod')
globalThis.platform = os.platform
`)
goModStr, _ := rt.Run(`
return goMod
`)
platformStr, _ := rt.Run(`
return platform
`)
test(t, "check std.loadFile", strings.Contains(u.String(goModStr), "apigo"), goModStr)
test(t, "check os.platform", u.String(platformStr) != "", platformStr)
rt.Close()
}
func TestAsync(t *testing.T) {
rt := gojs.New(nil)
rt.Start(`
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)
`)
timeoutValue, _ := rt.Run(`
return timeoutValue
`)
promiseValue, _ := rt.Run(`
return promiseValue
`)
test(t, "check timeoutValue", u.Int(timeoutValue) >= 300 && u.Int(timeoutValue) <= 400, timeoutValue)
test(t, "check promiseValue", u.Int(promiseValue) >= 200 && u.Int(promiseValue) <= 300, promiseValue)
rt.Close()
}
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`, nil)
}
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.Start(`
import obj from 'obj'
out = ''
obj.echoTimes(function(text){
out += text
})
`, nil)
}
tb.StopTimer()
ms2 := runtime.MemStats{}
runtime.ReadMemStats(&ms2)
runtime.GC()
ms3 := runtime.MemStats{}
runtime.ReadMemStats(&ms3)
fmt.Println(">>", ms1.HeapInuse, ms2.HeapInuse, ms3.HeapInuse)
}