Files
90CNServer/server/internal/modules/dnf/guild/state_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

167 lines
6.2 KiB
Go

package guild
import (
"context"
"errors"
"testing"
"time"
dnfrepo "longheng.io/server/internal/modules/dnf/repository"
dnfrepomemory "longheng.io/server/internal/modules/dnf/repository/memory"
)
func TestRegistryLifecyclePersistsAndEnforcesAuthority(t *testing.T) {
ctx := context.Background()
repositories := dnfrepomemory.NewMemoryGroup()
now := time.Date(2026, 8, 19, 10, 0, 0, 0, time.Local)
master := dnfrepo.CharacterRecord{CharacterID: "1", AccountID: "dnf:1", Name: "master", Level: 90}
applicant := dnfrepo.CharacterRecord{CharacterID: "2", AccountID: "dnf:1", Name: "member", Level: 90}
registry := NewRegistry()
created, err := registry.Create(master, "guild-one", now)
if err != nil {
t.Fatal(err)
}
if created.ID != 1 || registry.NameAvailable("GUILD-ONE") {
t.Fatalf("created=%+v available=%t", created, registry.NameAvailable("GUILD-ONE"))
}
if err := registry.Apply(created.ID, applicant, "join", now.Add(time.Minute)); err != nil {
t.Fatal(err)
}
if _, err := registry.DecideApplication(created.ID, applicant.CharacterID, applicant.CharacterID, true, now); !errors.Is(err, ErrPermissionDenied) {
t.Fatalf("unauthorized approval error=%v", err)
}
member, err := registry.DecideApplication(created.ID, master.CharacterID, applicant.CharacterID, true, now.Add(2*time.Minute))
if err != nil || member.Grade != DefaultMemberGrade {
t.Fatalf("approved member=%+v error=%v", member, err)
}
if err := registry.ChangeGrade(master.CharacterID, applicant.CharacterID, 2, now.Add(3*time.Minute)); err != nil {
t.Fatal(err)
}
if err := registry.Delegate(master.CharacterID, applicant.CharacterID, now.Add(4*time.Minute)); err != nil {
t.Fatal(err)
}
if err := Save(ctx, repositories.Settings, registry, now); err != nil {
t.Fatal(err)
}
reloaded, err := Load(ctx, repositories.Settings)
if err != nil {
t.Fatal(err)
}
got, _, found := reloaded.GuildForCharacter(applicant.CharacterID)
if !found || got.MasterCharacterID != applicant.CharacterID || got.MasterName != applicant.Name {
t.Fatalf("reloaded guild=%+v found=%t", got, found)
}
}
func TestRegistryInviteReplyAndDailyAttendance(t *testing.T) {
now := time.Date(2026, 8, 19, 9, 0, 0, 0, time.Local)
master := dnfrepo.CharacterRecord{CharacterID: "1", AccountID: "dnf:1", Name: "master", Level: 90}
target := dnfrepo.CharacterRecord{CharacterID: "2", AccountID: "dnf:1", Name: "target", Level: 80}
registry := NewRegistry()
guild, err := registry.Create(master, "guild-two", now)
if err != nil {
t.Fatal(err)
}
if err := registry.Invite(master.CharacterID, target, now); err != nil {
t.Fatal(err)
}
joined, err := registry.ReplyInvitation(target, true, now.Add(time.Minute))
if err != nil || joined.ID != guild.ID {
t.Fatalf("joined=%+v error=%v", joined, err)
}
if attended, err := registry.Attend(target.CharacterID, now.Add(2*time.Minute)); err != nil || attended {
t.Fatalf("same-day attendance=%t error=%v", attended, err)
}
if attended, err := registry.Attend(target.CharacterID, now.Add(25*time.Hour)); err != nil || !attended {
t.Fatalf("next-day attendance=%t error=%v", attended, err)
}
}
func TestRegistryMemoAuthority(t *testing.T) {
now := time.Date(2026, 8, 19, 9, 0, 0, 0, time.Local)
master := dnfrepo.CharacterRecord{CharacterID: "1", AccountID: "dnf:1", Name: "master", Level: 90}
member := dnfrepo.CharacterRecord{CharacterID: "2", AccountID: "dnf:1", Name: "member", Level: 80}
registry := NewRegistry()
guild, err := registry.Create(master, "guild-memo", now)
if err != nil {
t.Fatal(err)
}
if err := registry.Invite(master.CharacterID, member, now); err != nil {
t.Fatal(err)
}
if _, err := registry.ReplyInvitation(member, true, now); err != nil {
t.Fatal(err)
}
if err := registry.SetMemo(member.CharacterID, member.CharacterID, "self", now); err != nil {
t.Fatal(err)
}
if err := registry.SetMemo(member.CharacterID, master.CharacterID, "forged", now); !errors.Is(err, ErrPermissionDenied) {
t.Fatalf("member editing master memo error=%v", err)
}
if err := registry.SetMemo(master.CharacterID, member.CharacterID, "reviewed", now); err != nil {
t.Fatal(err)
}
if got := guild.Members[member.CharacterID].Memo; got != "reviewed" {
t.Fatalf("member memo=%q", got)
}
}
func TestRegistryMembershipTransitionsClearApplicationsInEveryGuild(t *testing.T) {
now := time.Date(2026, 8, 22, 14, 0, 0, 0, time.Local)
masterOne := dnfrepo.CharacterRecord{CharacterID: "1", AccountID: "dnf:1", Name: "master-one", Level: 90}
applicant := dnfrepo.CharacterRecord{CharacterID: "2", AccountID: "dnf:1", Name: "applicant", Level: 90}
masterTwo := dnfrepo.CharacterRecord{CharacterID: "3", AccountID: "dnf:1", Name: "master-two", Level: 90}
t.Run("create", func(t *testing.T) {
registry := NewRegistry()
guildOne, err := registry.Create(masterOne, "guild-one", now)
if err != nil {
t.Fatal(err)
}
guildTwo, err := registry.Create(masterTwo, "guild-two", now)
if err != nil {
t.Fatal(err)
}
if err := registry.Apply(guildOne.ID, applicant, "one", now); err != nil {
t.Fatal(err)
}
if err := registry.Apply(guildTwo.ID, applicant, "two", now); err != nil {
t.Fatal(err)
}
if _, err := registry.Create(applicant, "guild-three", now.Add(time.Minute)); err != nil {
t.Fatal(err)
}
if _, found := guildOne.Applications[applicant.CharacterID]; found {
t.Fatal("guild-one retained the creator's stale application")
}
if _, found := guildTwo.Applications[applicant.CharacterID]; found {
t.Fatal("guild-two retained the creator's stale application")
}
})
t.Run("approve", func(t *testing.T) {
registry := NewRegistry()
guildOne, err := registry.Create(masterOne, "guild-one", now)
if err != nil {
t.Fatal(err)
}
guildTwo, err := registry.Create(masterTwo, "guild-two", now)
if err != nil {
t.Fatal(err)
}
if err := registry.Apply(guildOne.ID, applicant, "one", now); err != nil {
t.Fatal(err)
}
if err := registry.Apply(guildTwo.ID, applicant, "two", now); err != nil {
t.Fatal(err)
}
if _, err := registry.DecideApplication(guildOne.ID, masterOne.CharacterID, applicant.CharacterID, true, now.Add(time.Minute)); err != nil {
t.Fatal(err)
}
if _, found := guildTwo.Applications[applicant.CharacterID]; found {
t.Fatal("another guild retained the new member's stale application")
}
})
}