Files
GaCy-GO/internal/common/banners_test.go
T

172 lines
4.7 KiB
Go

package common
import (
"encoding/json"
"gac-hkrpg-go/internal/testutil"
"os"
"path/filepath"
"runtime"
"testing"
)
func chdirRepoRoot(t *testing.T) {
t.Helper()
_, source, _, ok := runtime.Caller(0)
if !ok {
t.Fatal("cannot locate test helper source")
}
root := filepath.Clean(filepath.Join(filepath.Dir(source), "..", ".."))
if _, err := os.Stat(filepath.Join(root, "go.mod")); err != nil {
t.Fatalf("cannot locate repository root from %s: %v", source, err)
}
temporary := t.TempDir()
if err := testutil.CopyRuntime(root, temporary); err != nil {
t.Fatal(err)
}
t.Chdir(temporary)
}
func TestBannersConfigLoadAndVisibility(t *testing.T) {
chdirRepoRoot(t)
if err := LoadBannersConfig(); err != nil {
t.Fatalf("failed to load banners config: %v", err)
}
mode0 := GetVisibleBanners(0)
if len(mode0) < 13 {
t.Errorf("expected at least 13 visible banners for mode 0, got %d", len(mode0))
}
mode1 := GetVisibleBanners(1)
if len(mode1) < len(mode0) {
t.Errorf("expected mode 1 >= mode 0, got mode1=%d mode0=%d", len(mode1), len(mode0))
}
// Verify no duplicate IDs in mode 1
seen := make(map[uint32]bool)
for _, b := range mode1 {
if seen[b.ID] {
t.Fatalf("duplicate banner ID %d found in mode 1", b.ID)
}
seen[b.ID] = true
}
// Check mode 2 (character only)
mode2 := GetVisibleBanners(2)
if len(mode2) == 0 || len(mode2) >= len(mode1) {
t.Errorf("unexpected banner count for mode 2: %d", len(mode2))
}
// Check mode 3 (lightcone only)
mode3 := GetVisibleBanners(3)
if len(mode3) == 0 || len(mode3) >= len(mode1) {
t.Errorf("unexpected banner count for mode 3: %d", len(mode3))
}
}
func TestBannerProtoSerialization(t *testing.T) {
chdirRepoRoot(t)
if err := LoadBannersConfig(); err != nil {
t.Fatal(err)
}
// Check banner 1001 (Standard)
b1001 := FindGachaBanner(1001, 1)
if b1001 == nil {
t.Fatal("banner 1001 not found")
}
proto1001 := b1001.ToProtoInfo()
if proto1001.GachaId != 1001 {
t.Fatalf("expected gacha_id 1001, got %d", proto1001.GachaId)
}
if proto1001.GachaCeiling == nil || !proto1001.GachaCeiling.IsClaimed || len(proto1001.GachaCeiling.AvatarList) != 7 {
t.Fatalf("expected claimed gacha ceiling with 7 avatars, got %+v", proto1001.GachaCeiling)
}
// Check banner 2120 (AvatarUp)
b2120 := FindGachaBanner(2120, 1)
if b2120 == nil {
t.Fatal("banner 2120 not found")
}
proto2120 := b2120.ToProtoInfo()
if proto2120.GachaId != 2120 {
t.Fatalf("expected gacha_id 2120, got %d", proto2120.GachaId)
}
if len(proto2120.ONIHOMCELJK) == 0 || proto2120.ONIHOMCELJK[0] != 1505 {
t.Fatalf("expected featured 5-star 1505 in wire #5, got %+v", proto2120.ONIHOMCELJK)
}
if len(proto2120.ItemDetailList) != 1 || proto2120.ItemDetailList[0] != 11 {
t.Fatalf("expected AvatarUp marker 11 in ItemDetailList, got %+v", proto2120.ItemDetailList)
}
if len(proto2120.PrizeItemList) == 0 {
t.Fatal("expected PrizeItemList to contain rateUp items")
}
}
func TestPityProgression(t *testing.T) {
var state GachaPityState
if FiveStarChance90(1) != 0.006 {
t.Fatalf("expected base 5-star chance 0.006, got %f", FiveStarChance90(1))
}
if FiveStarChance90(76) != 0.324 {
t.Fatalf("expected soft pity 5-star chance 0.324, got %f", FiveStarChance90(76))
}
if FiveStarChance90(90) != 1.0 {
t.Fatalf("expected hard pity 5-star chance 1.0, got %f", FiveStarChance90(90))
}
// Test pity state transitions
state.RecordThreeStar()
if state.PullsSinceFiveStar != 1 || state.PullsSinceFourStarOrHigher != 1 || state.TotalPulls != 1 {
t.Fatalf("unexpected state after 3-star: %+v", state)
}
state.RecordFourStar()
if state.PullsSinceFiveStar != 2 || state.PullsSinceFourStarOrHigher != 0 || state.TotalPulls != 2 {
t.Fatalf("unexpected state after 4-star: %+v", state)
}
state.RecordFiveStar()
if state.PullsSinceFiveStar != 0 || state.PullsSinceFourStarOrHigher != 0 || state.TotalPulls != 3 {
t.Fatalf("unexpected state after 5-star: %+v", state)
}
}
func TestGachaRollExecution(t *testing.T) {
chdirRepoRoot(t)
if err := LoadBannersConfig(); err != nil {
t.Fatal(err)
}
player, err := LoadFreesrData()
if err != nil {
t.Fatal(err)
}
banner := FindGachaBanner(2120, 1)
if banner == nil {
t.Fatal("banner 2120 not found")
}
res, err := PerformGachaRolls(banner, 10, player)
if err != nil {
t.Fatalf("PerformGachaRolls failed: %v", err)
}
if len(res.Items) != 10 {
t.Fatalf("expected 10 items, got %d", len(res.Items))
}
// Verify persistence in freesr-data.json
raw, err := os.ReadFile("freesr-data.json")
if err != nil {
t.Fatal(err)
}
var doc map[string]json.RawMessage
if err := json.Unmarshal(raw, &doc); err != nil {
t.Fatal(err)
}
if _, ok := doc["gacha_pity"]; !ok {
t.Fatal("missing gacha_pity in freesr-data.json")
}
}