Files
ngzz-mc/internal/mods/mods_test.go

139 lines
3.9 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package mods
import (
"os"
"path/filepath"
"testing"
"time"
)
// TestLuaRegister 脚本注册方块/物品/配方与事件(Mod开发指南.md §4)。
func TestLuaRegister(t *testing.T) {
reg := NewRegistry()
m := NewLuaMod("test_mod", reg)
script := `
api.register_block{ id = "ruby_ore", hardness = 3.0, light = 0 }
api.register_item{ id = "ruby", stack = 64 }
api.register_recipe{ type = "crafting_shaped", pattern = {"RRR","R R","RRR"}, result = {item = "ruby_block"} }
`
if err := m.Load(script); err != nil {
t.Fatalf("加载失败: %v", err)
}
entries := reg.Entries()
if len(entries) != 3 {
t.Fatalf("注册条目期望 3,实际 %d", len(entries))
}
if reg.Gen("test_mod") != 1 {
t.Fatalf("代数期望 1,实际 %d", reg.Gen("test_mod"))
}
// 方块数据完整性
found := false
for _, e := range entries {
if e.Key == "block:ruby_ore" {
found = true
if d, ok := e.Data.(map[string]any); !ok || d["hardness"] != 3.0 {
t.Fatalf("方块数据异常: %+v", e.Data)
}
}
}
if !found {
t.Fatal("缺少 block:ruby_ore 注册")
}
}
// TestHotReload 热重载:新脚本替换旧注册(generation 机制,热更新.md §4.1)。
func TestHotReload(t *testing.T) {
reg := NewRegistry()
m := NewLuaMod("hot_mod", reg)
if err := m.Load(`api.register_block{ id = "old_block" }`); err != nil {
t.Fatalf("首次加载失败: %v", err)
}
// 热重载:注册新方块
if err := m.Load(`api.register_block{ id = "new_block" }`); err != nil {
t.Fatalf("重载失败: %v", err)
}
if reg.Gen("hot_mod") != 2 {
t.Fatalf("重载后代数期望 2,实际 %d", reg.Gen("hot_mod"))
}
for _, e := range reg.Entries() {
if e.Key == "block:old_block" {
t.Fatal("旧代注册未回收")
}
}
}
// TestReloadRollback 坏脚本回滚:保留旧版本(热更新.md §4.2)。
func TestReloadRollback(t *testing.T) {
reg := NewRegistry()
m := NewLuaMod("rollback_mod", reg)
if err := m.Load(`api.register_block{ id = "good_block" }`); err != nil {
t.Fatalf("首次加载失败: %v", err)
}
// 语法错误脚本:重载失败,旧版保留
if err := m.Load(`api.register_block{ id = `); err == nil {
t.Fatal("坏脚本应报错")
}
if reg.Gen("rollback_mod") != 1 {
t.Fatalf("回滚后代数应保持 1,实际 %d", reg.Gen("rollback_mod"))
}
found := false
for _, e := range reg.Entries() {
if e.Key == "block:good_block" {
found = true
}
}
if !found {
t.Fatal("回滚后旧注册丢失")
}
}
// TestSandbox 沙箱:os/io 库不可用(Mod开发指南.md §6)。
func TestSandbox(t *testing.T) {
reg := NewRegistry()
m := NewLuaMod("sandbox_mod", reg)
if err := m.Load(`os.exit(0)`); err == nil {
t.Fatal("沙箱应禁止 os 库")
}
}
// TestWatcher 文件监听热重载(热更新.md §4.5 防抖)。
func TestWatcher(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "init.lua")
if err := os.WriteFile(path, []byte(`api.register_block{ id = "v1" }`), 0o644); err != nil {
t.Fatalf("写脚本失败: %v", err)
}
reg := NewRegistry()
m := NewLuaMod("watched_mod", reg)
reload := func() error {
b, err := os.ReadFile(path)
if err != nil {
return err
}
return m.Load(string(b))
}
w, err := NewWatcher()
if err != nil {
t.Fatalf("创建监听器失败: %v", err)
}
defer w.Close()
if err := w.WatchFile(path, reload); err != nil {
t.Fatalf("监听失败: %v", err)
}
go w.Run()
if err := reload(); err != nil {
t.Fatalf("初始加载失败: %v", err)
}
// 修改文件 → 防抖后自动重载
if err := os.WriteFile(path, []byte(`api.register_block{ id = "v2" }`), 0o644); err != nil {
t.Fatalf("写脚本失败: %v", err)
}
deadline := time.Now().Add(5 * time.Second)
for reg.Gen("watched_mod") != 2 && time.Now().Before(deadline) {
time.Sleep(50 * time.Millisecond)
}
if reg.Gen("watched_mod") != 2 {
t.Fatalf("文件监听未触发重载(代数 %d)", reg.Gen("watched_mod"))
}
}