refactor(common): 重构 Conn 实体并优化地图进入逻辑
- 优化 Conn 实体的 SendPack 方法,提高代码复用性 - 添加 goja 模块到 go.work 文件 - 重构地图进入逻辑,增加玩家广播和刷怪功能 - 调整 OutInfo 结构中的 Vip 和 Viped 字段类型 - 简化 MonsterRefresh 结构体定义
This commit is contained in:
309
common/utils/goja/func_test.go
Normal file
309
common/utils/goja/func_test.go
Normal file
@@ -0,0 +1,309 @@
|
||||
package goja
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFuncProto(t *testing.T) {
|
||||
const SCRIPT = `
|
||||
"use strict";
|
||||
function A() {}
|
||||
A.__proto__ = Object;
|
||||
A.prototype = {};
|
||||
|
||||
function B() {}
|
||||
B.__proto__ = Object.create(null);
|
||||
var thrown = false;
|
||||
try {
|
||||
delete B.prototype;
|
||||
} catch (e) {
|
||||
thrown = e instanceof TypeError;
|
||||
}
|
||||
thrown;
|
||||
`
|
||||
testScript(SCRIPT, valueTrue, t)
|
||||
}
|
||||
|
||||
func TestFuncPrototypeRedefine(t *testing.T) {
|
||||
const SCRIPT = `
|
||||
let thrown = false;
|
||||
try {
|
||||
Object.defineProperty(function() {}, "prototype", {
|
||||
set: function(_value) {},
|
||||
});
|
||||
} catch (e) {
|
||||
if (e instanceof TypeError) {
|
||||
thrown = true;
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
thrown;
|
||||
`
|
||||
|
||||
testScript(SCRIPT, valueTrue, t)
|
||||
}
|
||||
|
||||
func TestFuncExport(t *testing.T) {
|
||||
vm := New()
|
||||
typ := reflect.TypeOf((func(FunctionCall) Value)(nil))
|
||||
|
||||
f := func(expr string, t *testing.T) {
|
||||
v, err := vm.RunString(expr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if actualTyp := v.ExportType(); actualTyp != typ {
|
||||
t.Fatalf("Invalid export type: %v", actualTyp)
|
||||
}
|
||||
ev := v.Export()
|
||||
if actualTyp := reflect.TypeOf(ev); actualTyp != typ {
|
||||
t.Fatalf("Invalid export value: %v", ev)
|
||||
}
|
||||
}
|
||||
|
||||
t.Run("regular function", func(t *testing.T) {
|
||||
f("(function() {})", t)
|
||||
})
|
||||
|
||||
t.Run("arrow function", func(t *testing.T) {
|
||||
f("(()=>{})", t)
|
||||
})
|
||||
|
||||
t.Run("method", func(t *testing.T) {
|
||||
f("({m() {}}).m", t)
|
||||
})
|
||||
|
||||
t.Run("class", func(t *testing.T) {
|
||||
f("(class {})", t)
|
||||
})
|
||||
}
|
||||
|
||||
func TestFuncWrapUnwrap(t *testing.T) {
|
||||
vm := New()
|
||||
f := func(a int, b string) bool {
|
||||
return a > 0 && b != ""
|
||||
}
|
||||
var f1 func(int, string) bool
|
||||
v := vm.ToValue(f)
|
||||
if et := v.ExportType(); et != reflect.TypeOf(f1) {
|
||||
t.Fatal(et)
|
||||
}
|
||||
err := vm.ExportTo(v, &f1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !f1(1, "a") {
|
||||
t.Fatal("not true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWrappedFunc(t *testing.T) {
|
||||
vm := New()
|
||||
f := func(a int, b string) bool {
|
||||
return a > 0 && b != ""
|
||||
}
|
||||
vm.Set("f", f)
|
||||
const SCRIPT = `
|
||||
assert.sameValue(typeof f, "function");
|
||||
const s = f.toString()
|
||||
assert(s.endsWith("TestWrappedFunc.func1() { [native code] }"), s);
|
||||
assert(f(1, "a"));
|
||||
assert(!f(0, ""));
|
||||
`
|
||||
vm.testScriptWithTestLib(SCRIPT, _undefined, t)
|
||||
}
|
||||
|
||||
func TestWrappedFuncErrorPassthrough(t *testing.T) {
|
||||
vm := New()
|
||||
e := errors.New("test")
|
||||
f := func(a int) error {
|
||||
if a > 0 {
|
||||
return e
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var f1 func(a int64) error
|
||||
err := vm.ExportTo(vm.ToValue(f), &f1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := f1(1); err != e {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleAssertConstructor() {
|
||||
vm := New()
|
||||
res, err := vm.RunString(`
|
||||
(class C {
|
||||
constructor(x) {
|
||||
this.x = x;
|
||||
}
|
||||
})
|
||||
`)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if ctor, ok := AssertConstructor(res); ok {
|
||||
obj, err := ctor(nil, vm.ToValue("Test"))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Print(obj.Get("x"))
|
||||
} else {
|
||||
panic("Not a constructor")
|
||||
}
|
||||
// Output: Test
|
||||
}
|
||||
|
||||
type testAsyncCtx struct {
|
||||
group string
|
||||
refCount int
|
||||
}
|
||||
|
||||
type testAsyncContextTracker struct {
|
||||
ctx *testAsyncCtx
|
||||
logFunc func(...interface{})
|
||||
resumed bool
|
||||
}
|
||||
|
||||
func (s *testAsyncContextTracker) Grab() interface{} {
|
||||
ctx := s.ctx
|
||||
if ctx != nil {
|
||||
s.logFunc("Grab", ctx.group)
|
||||
ctx.refCount++
|
||||
}
|
||||
return ctx
|
||||
}
|
||||
|
||||
func (s *testAsyncContextTracker) Resumed(trackingObj interface{}) {
|
||||
s.logFunc("Resumed", trackingObj)
|
||||
if s.resumed {
|
||||
panic("Nested Resumed() calls")
|
||||
}
|
||||
s.ctx = trackingObj.(*testAsyncCtx)
|
||||
s.resumed = true
|
||||
}
|
||||
|
||||
func (s *testAsyncContextTracker) releaseCtx() {
|
||||
s.ctx.refCount--
|
||||
if s.ctx.refCount < 0 {
|
||||
panic("refCount < 0")
|
||||
}
|
||||
if s.ctx.refCount == 0 {
|
||||
s.logFunc(s.ctx.group, "is finished")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *testAsyncContextTracker) Exited() {
|
||||
s.logFunc("Exited")
|
||||
if s.ctx != nil {
|
||||
s.releaseCtx()
|
||||
s.ctx = nil
|
||||
}
|
||||
s.resumed = false
|
||||
}
|
||||
|
||||
func TestAsyncContextTracker(t *testing.T) {
|
||||
r := New()
|
||||
var tracker testAsyncContextTracker
|
||||
tracker.logFunc = t.Log
|
||||
|
||||
group := func(name string, asyncFunc func(FunctionCall) Value) Value {
|
||||
prevCtx := tracker.ctx
|
||||
defer func() {
|
||||
t.Log("Returned", name)
|
||||
tracker.releaseCtx()
|
||||
tracker.ctx = prevCtx
|
||||
}()
|
||||
tracker.ctx = &testAsyncCtx{
|
||||
group: name,
|
||||
refCount: 1,
|
||||
}
|
||||
t.Log("Set", name)
|
||||
return asyncFunc(FunctionCall{})
|
||||
}
|
||||
r.SetAsyncContextTracker(&tracker)
|
||||
r.Set("group", group)
|
||||
r.Set("check", func(expectedGroup, msg string) {
|
||||
var groupName string
|
||||
if tracker.ctx != nil {
|
||||
groupName = tracker.ctx.group
|
||||
}
|
||||
if groupName != expectedGroup {
|
||||
t.Fatalf("Unexpected group (%q), expected %q in %s", groupName, expectedGroup, msg)
|
||||
}
|
||||
t.Log("In", msg)
|
||||
})
|
||||
|
||||
t.Run("", func(t *testing.T) {
|
||||
_, err := r.RunString(`
|
||||
group("1", async () => {
|
||||
check("1", "line A");
|
||||
await 3;
|
||||
check("1", "line B");
|
||||
group("2", async () => {
|
||||
check("2", "line C");
|
||||
await 4;
|
||||
check("2", "line D");
|
||||
})
|
||||
}).then(() => {
|
||||
check("", "line E");
|
||||
})
|
||||
`)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("", func(t *testing.T) {
|
||||
_, err := r.RunString(`
|
||||
group("some", async () => {
|
||||
check("some", "line A");
|
||||
(async () => {
|
||||
check("some", "line B");
|
||||
await 1;
|
||||
check("some", "line C");
|
||||
await 2;
|
||||
check("some", "line D");
|
||||
})();
|
||||
check("some", "line E");
|
||||
});
|
||||
`)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("", func(t *testing.T) {
|
||||
_, err := r.RunString(`
|
||||
group("Main", async () => {
|
||||
check("Main", "0.1");
|
||||
await Promise.all([
|
||||
group("A", async () => {
|
||||
check("A", "1.1");
|
||||
await 1;
|
||||
check("A", "1.2");
|
||||
}),
|
||||
(async () => {
|
||||
check("Main", "3.1");
|
||||
})(),
|
||||
group("B", async () => {
|
||||
check("B", "2.1");
|
||||
await 2;
|
||||
check("B", "2.2");
|
||||
})
|
||||
]);
|
||||
check("Main", "0.2");
|
||||
});
|
||||
`)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user