160 lines
5.7 KiB
Go
160 lines
5.7 KiB
Go
package gameserver
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"gac-hkrpg-go/internal/common"
|
|
goproto "gac-hkrpg-go/protocol/proto"
|
|
)
|
|
|
|
func TestCurrencyWarsEntranceUsesCapturedRoomConditionWithoutMutatingScene(t *testing.T) {
|
|
scene := &common.LevelOutputConfig{SavedValues: map[string]int32{
|
|
"FSV_370GridFight": 0,
|
|
"unrelated": 7,
|
|
}}
|
|
group := common.CurrencyWarsRoomGroup{GroupID: 1}
|
|
group.Condition.Name = "FSV_370GridFight"
|
|
group.Condition.Comparison = "GreaterEqual"
|
|
group.Condition.Value = 1
|
|
entrance := common.CurrencyWarsEntrance{
|
|
EntryID: 2,
|
|
RoomGroups: []common.CurrencyWarsRoomGroup{group},
|
|
SavedValues: map[string]int32{"FSV_370GridFight": 2},
|
|
}
|
|
|
|
got, err := currencyWarsEntranceScene(scene, entrance)
|
|
if err != nil {
|
|
t.Fatalf("apply captured CW entrance profile: %v", err)
|
|
}
|
|
if got.SavedValues["FSV_370GridFight"] != 2 || got.SavedValues["unrelated"] != 7 {
|
|
t.Fatalf("CW entrance profile = %v; want selected and unrelated values preserved", got.SavedValues)
|
|
}
|
|
if scene.SavedValues["FSV_370GridFight"] != 0 {
|
|
t.Fatal("applying CW freeplay profile mutated shared scene data")
|
|
}
|
|
got.SavedValues["FSV_370GridFight"] = 99
|
|
if scene.SavedValues["FSV_370GridFight"] != 0 {
|
|
t.Fatal("returned CW scene shares its saved-value map with the original")
|
|
}
|
|
}
|
|
|
|
func TestCurrencyWarsSelectedEnemyBranchUsesSavedOneBasedChoice(t *testing.T) {
|
|
first := &goproto.KKBGIPCAGGH{IFIIOIIKJHO: 91}
|
|
second := &goproto.KKBGIPCAGGH{IFIIOIIKJHO: 92}
|
|
for _, tc := range []struct {
|
|
name string
|
|
selection uint32
|
|
branches []*goproto.KKBGIPCAGGH
|
|
want *goproto.KKBGIPCAGGH
|
|
wantErr string
|
|
}{
|
|
{name: "select first offered branch", selection: 1, branches: []*goproto.KKBGIPCAGGH{first, second}, want: first},
|
|
{name: "select second offered branch", selection: 2, branches: []*goproto.KKBGIPCAGGH{first, second}, want: second},
|
|
{name: "selection is required", selection: 0, branches: []*goproto.KKBGIPCAGGH{first}, wantErr: "outside"},
|
|
{name: "selection must be offered", selection: 2, branches: []*goproto.KKBGIPCAGGH{first}, wantErr: "outside"},
|
|
{name: "selected branch cannot be empty", selection: 1, branches: []*goproto.KKBGIPCAGGH{nil}, wantErr: "is empty"},
|
|
{name: "no offered branches", selection: 1, wantErr: "no offered plans"},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
got, err := cwSelectedEnemyBranch(&goproto.MDJBBILMHLC{MOADBALHMFD: tc.selection, BPDABHGFBFO: tc.branches})
|
|
if tc.wantErr != "" {
|
|
if err == nil || !strings.Contains(err.Error(), tc.wantErr) {
|
|
t.Fatalf("branch error = %v; want %q", err, tc.wantErr)
|
|
}
|
|
return
|
|
}
|
|
if err != nil {
|
|
t.Fatalf("resolve selected branch: %v", err)
|
|
}
|
|
if got != tc.want {
|
|
t.Fatalf("selected plan = %p; want %p", got, tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCurrencyWarsBattleAndRefreshRequestsUseTypedHandlers(t *testing.T) {
|
|
for _, name := range []string{
|
|
"GridFightEnterBattleStageCsReq",
|
|
"GridFightRefreshShopCsReq",
|
|
} {
|
|
t.Run(name, func(t *testing.T) {
|
|
id, ok := goproto.CmdIDByName[name]
|
|
if !ok {
|
|
t.Fatalf("protocol command table is missing %s", name)
|
|
}
|
|
if typedHandlers[uint16(id)] == nil {
|
|
t.Fatalf("implemented CW request %s has no typed handler", name)
|
|
}
|
|
if rawHandlers[uint16(id)] != nil {
|
|
t.Fatalf("CW request %s is registered through an untyped handler", name)
|
|
}
|
|
if _, ok := dummyResponses[uint16(id)]; ok {
|
|
t.Fatalf("CW request %s unexpectedly has a dummy response", name)
|
|
}
|
|
if !isDangerCmd(uint16(id)) {
|
|
t.Fatalf("CW request %s is not protected from dispatcher auto-replies", name)
|
|
}
|
|
if _, ok := goproto.RspIDByReqID[uint32(id)]; !ok {
|
|
t.Fatalf("test request %s has no paired response to protect", name)
|
|
}
|
|
})
|
|
}
|
|
|
|
getDataID, ok := goproto.CmdIDByName["GridFightGetDataCsReq"]
|
|
if !ok || typedHandlers[uint16(getDataID)] == nil {
|
|
t.Fatal("the verified CW bootstrap request must keep its typed handler")
|
|
}
|
|
}
|
|
|
|
func TestCurrencyWarsStartGameplayUsesCurrentTypedRequestHandler(t *testing.T) {
|
|
id := uint16(goproto.CmdIDByName["GridFightStartGamePlayCsReq"])
|
|
if typedHandlers[id] == nil {
|
|
t.Fatal("CW start request must have a typed gameplay handler")
|
|
}
|
|
if rawHandlers[id] != nil {
|
|
t.Fatal("CW start request must not use an untyped mode-observation handler")
|
|
}
|
|
if _, ok := dummyResponses[id]; ok {
|
|
t.Fatal("CW start request must not receive an empty response")
|
|
}
|
|
if !isDangerCmd(id) {
|
|
t.Fatal("CW start request must remain protected from dispatcher auto-replies")
|
|
}
|
|
if _, ok := goproto.RspIDByReqID[uint32(id)]; !ok {
|
|
t.Fatal("CW start request has no paired response in the current protocol table")
|
|
}
|
|
}
|
|
|
|
func TestCurrencyWarsEntranceRejectsUnsupportedOrUnmetConditions(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
value int32
|
|
comparison string
|
|
wantErr string
|
|
}{
|
|
{name: "condition unmet", value: 0, comparison: "GreaterEqual", wantErr: "condition is not satisfied"},
|
|
{name: "unsupported comparison", value: 2, comparison: "Equal", wantErr: "unsupported CW room comparison"},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
scene := &common.LevelOutputConfig{SavedValues: map[string]int32{"condition": 0}}
|
|
group := common.CurrencyWarsRoomGroup{GroupID: 1}
|
|
group.Condition.Name = "condition"
|
|
group.Condition.Comparison = tt.comparison
|
|
group.Condition.Value = 1
|
|
entrance := common.CurrencyWarsEntrance{
|
|
RoomGroups: []common.CurrencyWarsRoomGroup{group},
|
|
SavedValues: map[string]int32{"condition": tt.value},
|
|
}
|
|
if _, err := currencyWarsEntranceScene(scene, entrance); err == nil || !strings.Contains(err.Error(), tt.wantErr) {
|
|
t.Fatalf("entrance error = %v; want %q", err, tt.wantErr)
|
|
}
|
|
if scene.SavedValues["condition"] != 0 {
|
|
t.Fatal("rejected CW profile mutated shared scene data")
|
|
}
|
|
})
|
|
}
|
|
}
|