Files
bd2/go/internal/server/gamedata/first_gacha_test.go
T

174 lines
5.6 KiB
Go

package gamedata
import (
"database/sql"
"os"
"strings"
"testing"
"bd2server/internal/server/wire"
)
func firstGachaTestProgram() *FirstGachaRewardGroup {
return &FirstGachaRewardGroup{ID: 77, DropCount: 1, DropType: 1, Entries: []FirstGachaRewardEntry{
{ItemType: 11, ItemID: 5001, Count: 1, Weight: 1},
{ItemType: 9, ItemID: 78, Count: 1, Weight: 1, Group: &FirstGachaRewardGroup{ID: 78, DropCount: 2, Entries: []FirstGachaRewardEntry{
{ItemType: 10, ItemID: 1001, Count: 1, Weight: 25},
{ItemType: 10, ItemID: 1002, Count: 1, Weight: 75},
}}},
}}
}
func TestFirstGachaMixedProgramPreservesCountsAndBranchWeights(t *testing.T) {
design, err := NewFirstGachaDesign(GachaGroupDesign{ID: 2, GachaSubType: 3, TenTimeGachaID: 20}, 20, 3, firstGachaTestProgram(),
map[uint64]CharacterDesign{5001: {ID: 500, HP: 100}},
map[uint64]EquipmentDesign{1001: {ID: 1001, Grade: 2}, 1002: {ID: 1002, Grade: 3}})
if err != nil {
t.Fatal(err)
}
values := []uint64{24, 25}
roll, err := design.roll(func(limit uint64) (uint64, error) {
if limit != 100 {
t.Fatalf("weight total=%d want=100", limit)
}
value := values[0]
values = values[1:]
return value, nil
})
if err != nil || len(roll) != 3 || roll[0] != (FirstGachaReward{Type: 11, ID: 5001}) || roll[1].ID != 1001 || roll[2].ID != 1002 {
t.Fatalf("roll=%v err=%v", roll, err)
}
if len(design.CostumeCatalog().Gachas) != 0 {
t.Fatal("starter design exposed a zero-price ordinary product")
}
if _, ok := design.Character(5001); !ok {
t.Fatal("starter character metadata missing")
}
}
func TestFirstGachaRejectsInvalidPrograms(t *testing.T) {
for _, kind := range []string{"cycle", "unsupported type", "mismatched weighted count", "zero weight", "excessive count"} {
t.Run(kind, func(t *testing.T) {
g := firstGachaTestProgram()
switch kind {
case "cycle":
g.Entries[1].ItemID = g.ID
g.Entries[1].Group = g
case "unsupported type":
g.Entries[0].ItemType = 8
case "mismatched weighted count":
g.Entries[1].Group.Entries[0].Count = 2
case "zero weight":
g.Entries[0].Weight = 0
case "excessive count":
g.Entries[1].Group.DropCount = 101
}
if _, err := firstGachaRewardCount(g, map[*FirstGachaRewardGroup]bool{}); err == nil {
t.Fatal("invalid mixed reward program accepted")
}
})
}
}
func TestFirstGachaLoaderRejectsNonStarterOrPricedMetadata(t *testing.T) {
for _, bad := range []string{"group subtype", "group type", "cash product", "scheduled", "priced", "ticket", "daily allowance"} {
t.Run(bad, func(t *testing.T) {
db, err := sql.Open("sqlite", ":memory:")
if err != nil {
t.Fatal(err)
}
defer db.Close()
db.SetMaxOpenConns(1)
for _, table := range []string{"GameDefaultTable", "GachaGroupTable", "GachaTable"} {
if _, err := db.Exec("CREATE TABLE " + table + " (id INTEGER PRIMARY KEY,ProtoBuf BLOB)"); err != nil {
t.Fatal(err)
}
}
group := wire.AppendVarint(nil, 18, 2)
group = wire.AppendVarint(group, 16, 3)
group = wire.AppendVarint(group, 33, 20)
product := wire.AppendVarint(nil, 9, 20)
product = wire.AppendVarint(product, 5, 10)
product = wire.AppendVarint(product, 7, 20)
switch bad {
case "group subtype":
group, _, err = wire.ReplaceVarint(group, 16, 1)
case "group type":
group = wire.AppendVarint(group, 17, 1)
case "cash product":
group = wire.AppendVarint(group, 3, 123)
case "scheduled":
group = wire.AppendVarint(group, 28, 1)
case "priced":
product = wire.AppendVarint(product, 10, 200)
case "ticket":
product = wire.AppendVarint(product, 8, 450000)
case "daily allowance":
product = wire.AppendVarint(product, 4, 1)
}
if err != nil {
t.Fatal(err)
}
for _, row := range []struct {
table string
id uint64
raw []byte
}{{"GameDefaultTable", 0, wire.AppendVarint(nil, 46, 2)}, {"GachaGroupTable", 2, group}, {"GachaTable", 20, product}} {
if _, err := db.Exec("INSERT INTO "+row.table+" VALUES (?,?)", row.id, row.raw); err != nil {
t.Fatal(err)
}
}
_, err = loadFirstGacha(db)
want := "unsupported field"
if bad == "ticket" {
want = "cannot consume tickets"
}
if err == nil || !strings.Contains(err.Error(), want) {
t.Fatalf("metadata was not rejected before reading rewards: err=%v want=%q", err, want)
}
})
}
}
func TestFirstGachaAgainstInstalledVersion23510(t *testing.T) {
root := os.Getenv("BD2_TEST_GAMEDATA_ROOT")
if root == "" {
t.Skip("set BD2_TEST_GAMEDATA_ROOT for installed GameData integration test")
}
design, err := LoadFirstGacha(root, "20260923193640")
if err != nil {
t.Fatal(err)
}
if design.Group.ID != 2 || design.GachaID != 20 || design.Count != 10 || design.Group.PointCount != 0 || len(design.RewardGroup.Entries) != 6 {
t.Fatalf("design=%+v", design)
}
// Current GameData gives one five-star, one four-star, three three-star
// costumes and five exclusive-equipment instances in every reroll.
for i := 0; i < 20; i++ {
roll, err := design.Roll()
if err != nil {
t.Fatal(err)
}
var costumes, equipment int
for _, reward := range roll {
switch reward.Type {
case 11:
costumes++
if _, ok := design.Character(reward.ID); !ok {
t.Fatalf("unknown costume %d", reward.ID)
}
case 10:
equipment++
if _, ok := design.EquipmentCatalog().equipment[reward.ID]; !ok {
t.Fatalf("unknown equipment %d", reward.ID)
}
default:
t.Fatalf("unexpected reward type %d", reward.Type)
}
}
if len(roll) != 10 || costumes != 5 || equipment != 5 {
t.Fatalf("mixed draw has costumes=%d equipment=%d results=%v", costumes, equipment, roll)
}
}
}