Files
90CNServer/pvf/internal/pvf/script_view_test.go
T
hanfuit 645b64fe21 DNF90 服务端与启动器完整源码(含 GM 工具功能增强)
服务端(Go):
- GM 塞背包/带属性装备发放:在线角色推送 op14 增量物品行,背包实时刷新,无需回角色选择界面
- GM 改金币/改等级:去掉在线拒绝,落库后推送 op14 钱包/op37 等级状态,在线实时刷新
- 等级端点统一切换到新版 GMSetCharacterLevel(自带在线刷新)
- 无限/锁死疲劳模式 + 燃烧疲劳:每房间消耗 2 点、打怪与通关经验双倍
- 燃烧疲劳开关时给所有在线角色推送系统提示(op12 mode 0)
- 深渊史诗掉率:GM 全局倍率 + 城镇增益药剂窗口倍率,真实接入掉落结算

启动器(Python/JS):
- 标题栏自绘、窗口 1204x717、禁止拖拽改大小、仅最小化/关闭
- GM 工具:疲劳与燃烧、深渊史诗掉率、拍卖行上架(单一定价对齐)
- 拍卖行上架前端对齐服务端单一价格语义,修复 400 报错
2026-11-04 14:31:55 +08:00

113 lines
3.5 KiB
Go

package pvf
import (
"strings"
"testing"
)
func TestParseScriptViewFlatAndDuplicateSections(t *testing.T) {
view := ParseScriptView("[rarity]\n3\n[name]\n`first`\n[rarity]\n4")
var sections, rarityTokens int
for _, element := range view.Elements {
if element.Kind == ScriptElementSection {
sections++
}
if element.Kind == ScriptElementToken && element.Section == "rarity" {
rarityTokens++
if element.Index != 0 {
t.Fatalf("rarity token index = %d, want 0", element.Index)
}
}
}
if sections != 3 || rarityTokens != 2 {
t.Fatalf("sections=%d rarityTokens=%d", sections, rarityTokens)
}
}
func TestParseScriptViewNestedDirectTokens(t *testing.T) {
view := ParseScriptView("[parent]\n1\n[child]\n2\n[/child]\n3\n[/parent]")
got := make([]string, 0)
for _, element := range view.Elements {
if element.Kind == ScriptElementToken {
got = append(got, element.Section+":"+element.Value)
}
}
want := []string{"parent:1", "child:2", "parent:3"}
if len(got) != len(want) {
t.Fatalf("tokens = %#v", got)
}
for i := range want {
if got[i] != want[i] {
t.Fatalf("tokens = %#v, want %#v", got, want)
}
}
}
func TestParseScriptViewPairedChildInsideUnpairedSection(t *testing.T) {
view := ParseScriptViewWithNestedSections("[independent drop]\n1 2\n[list]\n100 200\n[/list]\n3 4\n[next]\n5", func(parent, child string) bool {
return parent == "independent drop" && child == "list"
})
var parentID int
var got []string
for _, element := range view.Elements {
if element.Kind != ScriptElementToken {
continue
}
if element.Value == "1" {
parentID = element.SectionID
}
got = append(got, element.Section+":"+element.Value)
if element.Value == "3" && (element.SectionID != parentID || element.Index != 2) {
t.Fatalf("token after list did not resume parent: %#v", element)
}
}
want := []string{"independent drop:1", "independent drop:2", "list:100", "list:200", "independent drop:3", "independent drop:4", "next:5"}
if strings.Join(got, ",") != strings.Join(want, ",") {
t.Fatalf("tokens = %#v, want %#v", got, want)
}
}
func TestParseScriptViewUsesUTF16Offsets(t *testing.T) {
view := ParseScriptView("[name]\n`😀中`")
for _, element := range view.Elements {
if element.Kind != ScriptElementToken {
continue
}
if element.Start != 7 || element.End != 12 {
t.Fatalf("range = [%d,%d), want [7,12)", element.Start, element.End)
}
return
}
t.Fatal("name token not found")
}
func TestParseScriptViewNormalizesLineEndingOffsets(t *testing.T) {
text := "[name]\n`line1\r\nline2`\r[rarity]\r\n3"
normalized := strings.NewReplacer("\r\n", "\n", "\r", "\n").Replace(text)
view := ParseScriptView(text)
var section, token *ScriptElement
for i := range view.Elements {
element := &view.Elements[i]
if element.Kind == ScriptElementSection && element.Section == "rarity" {
section = element
}
if element.Kind == ScriptElementToken && element.Section == "rarity" {
token = element
}
}
if section == nil || token == nil {
t.Fatalf("rarity elements not found: %#v", view.Elements)
}
wantSectionStart := strings.Index(normalized, "[rarity]")
wantSectionEnd := wantSectionStart + len("[rarity]")
wantTokenStart := strings.LastIndex(normalized, "3")
if section.Start != wantSectionStart || section.End != wantSectionEnd {
t.Fatalf("section range = [%d,%d), want [%d,%d)", section.Start, section.End, wantSectionStart, wantSectionEnd)
}
if token.Start != wantTokenStart || token.End != wantTokenStart+1 {
t.Fatalf("token range = [%d,%d), want [%d,%d)", token.Start, token.End, wantTokenStart, wantTokenStart+1)
}
}