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

179 lines
5.8 KiB
Go

package common
import (
"bytes"
"encoding/json"
"os"
"strings"
"testing"
)
func loadCurrencyWarsTestCatalog(t *testing.T) *CurrencyWarsCatalog {
t.Helper()
raw, err := ReadResourceFile("resources/CurrencyWarsCatalog.json")
if err != nil {
t.Fatal(err)
}
var catalog CurrencyWarsCatalog
if err := json.Unmarshal(raw, &catalog); err != nil {
t.Fatal(err)
}
if err := catalog.validate(catalog.ClientVersion); err != nil {
t.Fatalf("validate captured CW catalog: %v", err)
}
if err := catalog.resolveActivity(); err != nil {
t.Fatalf("resolve captured CW activities: %v", err)
}
if err := catalog.validateRoutes(); err != nil {
t.Fatalf("validate captured CW routes: %v", err)
}
if err := catalog.validateCapturedGameplay(); err != nil {
t.Fatalf("validate captured CW role/stage data: %v", err)
}
if err := catalog.validateEntrance(); err != nil {
t.Fatalf("validate captured CW entrance: %v", err)
}
return &catalog
}
func TestCurrencyWarsCapturedCatalogAndConfiguredVersion(t *testing.T) {
catalog := loadCurrencyWarsTestCatalog(t)
if len(catalog.ActivitySchedules()) == 0 || len(catalog.CapturedRoles) == 0 || len(catalog.CapturedStages) == 0 {
t.Fatal("captured CW activity, role, or stage data is empty")
}
if err := catalog.validate(catalog.ClientVersion + "-mismatch"); err == nil {
t.Fatal("CW catalog accepted a different Client version")
}
}
func TestCurrencyWarsCatalogLookupsReturnIsolatedCopies(t *testing.T) {
catalog := loadCurrencyWarsTestCatalog(t)
roleBefore, err := catalog.CapturedRole(catalog.CapturedRoles[0].Config.ID)
if err != nil {
t.Fatal(err)
}
role, err := catalog.CapturedRole(catalog.CapturedRoles[0].Config.ID)
if err != nil {
t.Fatal(err)
}
if len(role.Config.TraitList) > 0 {
role.Config.TraitList[0]++
}
roleAfter, err := catalog.CapturedRole(catalog.CapturedRoles[0].Config.ID)
if err != nil {
t.Fatal(err)
}
if len(roleBefore.Config.TraitList) > 0 && roleAfter.Config.TraitList[0] != roleBefore.Config.TraitList[0] {
t.Fatal("mutating a returned CW role changed catalog data")
}
stageBefore, err := catalog.CapturedStage(catalog.CapturedStages[0].ID)
if err != nil {
t.Fatal(err)
}
stage, err := catalog.CapturedStage(catalog.CapturedStages[0].ID)
if err != nil {
t.Fatal(err)
}
if len(stage.EnvironmentBuffList) > 0 {
stage.EnvironmentBuffList[0]++
}
stageAfter, err := catalog.CapturedStage(catalog.CapturedStages[0].ID)
if err != nil {
t.Fatal(err)
}
if len(stageBefore.EnvironmentBuffList) > 0 && stageAfter.EnvironmentBuffList[0] != stageBefore.EnvironmentBuffList[0] {
t.Fatal("mutating a returned CW stage changed catalog data")
}
routeID := catalog.StageRoutes[0].RouteID
routeBefore, err := catalog.RouteNodes(routeID)
if err != nil {
t.Fatal(err)
}
route, err := catalog.RouteNodes(routeID)
if err != nil {
t.Fatal(err)
}
route[0].NodeTemplateID++
routeAfter, err := catalog.RouteNodes(routeID)
if err != nil {
t.Fatal(err)
}
if routeAfter[0].NodeTemplateID != routeBefore[0].NodeTemplateID {
t.Fatal("mutating a returned CW route changed catalog data")
}
}
func TestCurrencyWarsCapturedEconomyRules(t *testing.T) {
catalog := loadCurrencyWarsTestCatalog(t)
role := catalog.CapturedRoles[0]
price, err := catalog.BaseSalePrice(role.Config.ID, role.DefaultStar)
if err != nil {
t.Fatal(err)
}
if price != role.DefaultSellPrice {
t.Fatalf("captured base sale price = %d, want native row value %d", price, role.DefaultSellPrice)
}
if _, err := catalog.BaseSalePrice(role.Config.ID, role.MaxStar+1); err == nil {
t.Fatal("sale price accepted an uncaptured star rank")
}
deposit, err := catalog.IntegerRule("GridFight_DepositPerInterest")
if err != nil || deposit <= 0 {
t.Fatalf("invalid captured deposit rule %d: %v", deposit, err)
}
gold := uint32(deposit*3 + deposit/2)
interest, err := catalog.BaseInterest(gold, 2)
if err != nil || interest != 2 {
t.Fatalf("base interest = %d, %v; want integer division capped at 2", interest, err)
}
zeroCapped, err := catalog.BaseInterest(gold, 0)
if err != nil || zeroCapped != 0 {
t.Fatalf("zero-cap interest = %d, %v; want 0", zeroCapped, err)
}
}
func TestCurrencyWarsSnapshotRevisionPreventsStaleWrites(t *testing.T) {
t.Chdir(t.TempDir())
const assemblyHash = "abababababababababababababababababababababababababababababababab"
if err := os.WriteFile("persistent", []byte(`{"other_service":{"counter":9007199254740993}}`), 0600); err != nil {
t.Fatal(err)
}
first := NewCurrencyWarsSnapshot(42, "4.6.53", assemblyHash, []byte{0x0a, 0x01, 0x01})
revision, err := CommitCurrencyWarsSnapshot(0, first)
if err != nil || revision != 1 {
t.Fatalf("first CW commit = revision %d, %v; want revision 1", revision, err)
}
stale := NewCurrencyWarsSnapshot(42, "4.6.53", assemblyHash, []byte{0x0a, 0x01, 0x02})
if _, err := CommitCurrencyWarsSnapshot(0, stale); err != ErrCurrencyWarsSaveConflict {
t.Fatalf("stale CW commit error = %v; want save conflict", err)
}
saved, err := ReadCurrencyWarsSnapshot(42, "4.6.53", assemblyHash)
if err != nil || saved.Revision != 1 || !bytes.Equal(saved.WireData, first.WireData) {
t.Fatalf("stale write changed saved CW snapshot: %+v, %v", saved, err)
}
next := NewCurrencyWarsSnapshot(42, "4.6.53", assemblyHash, []byte{0x0a, 0x01, 0x03})
revision, err = CommitCurrencyWarsSnapshot(1, next)
if err != nil || revision != 2 {
t.Fatalf("next CW commit = revision %d, %v; want revision 2", revision, err)
}
if _, err := ReadCurrencyWarsSnapshot(42, "6.1", assemblyHash); err == nil {
t.Fatal("CW snapshot accepted a different Client version")
}
persistent, err := os.ReadFile("persistent")
if err != nil {
t.Fatal(err)
}
if !bytes.Contains(persistent, []byte(`"other_service"`)) || !bytes.Contains(persistent, []byte("9007199254740993")) {
t.Fatalf("CW commit failed to preserve unrelated persistent data: %s", strings.TrimSpace(string(persistent)))
}
}