go_games_collection/corpsestarch_game_test.go

235 lines
8.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"testing"
"time"
)
func csT(offsetSec int) time.Time {
base := time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC)
return base.Add(time.Duration(offsetSec) * time.Second)
}
func TestNewCorpseStarchGameInitialState(t *testing.T) {
g := NewCorpseStarchGame(csT(0))
if g.Starch != 0 || g.TotalEarned != 0 {
t.Fatalf("новая партия должна начинаться с нулевого запаса")
}
if g.ClickYield != 1 {
t.Errorf("ожидался базовый доход клика 1, получено %v", g.ClickYield)
}
if len(g.ServitorCounts) != len(corpseStarchServitorDefs) {
t.Errorf("количество счётчиков сервиторов должно совпадать с числом тиров")
}
}
func TestRequisitionAddsClickYield(t *testing.T) {
g := NewCorpseStarchGame(csT(0))
g.Requisition(csT(0))
if g.Starch != 1 || g.TotalEarned != 1 {
t.Errorf("ожидался запас 1 после одной реквизиции, получено %v/%v", g.Starch, g.TotalEarned)
}
g.Requisition(csT(1))
if g.Starch != 2 {
t.Errorf("ожидался запас 2 после двух реквизиций, получено %v", g.Starch)
}
}
func TestTickAccruesPassiveIncome(t *testing.T) {
g := NewCorpseStarchGame(csT(0))
g.ServitorCounts[0] = 2 // 2 сервочерепа по 0.5/сек = 1/сек
g.Tick(csT(10))
if g.Starch != 10 {
t.Errorf("ожидался запас 10 после 10 секунд по 1/сек, получено %v", g.Starch)
}
if g.TotalEarned != 10 {
t.Errorf("TotalEarned тоже должен был вырасти на 10, получено %v", g.TotalEarned)
}
}
func TestTickWithNoElapsedTimeDoesNothing(t *testing.T) {
g := NewCorpseStarchGame(csT(5))
g.ServitorCounts[0] = 5
g.Tick(csT(5))
if g.Starch != 0 {
t.Errorf("без прошедшего времени доход не должен начисляться, получено %v", g.Starch)
}
}
func TestSectionsUnlockProgressively(t *testing.T) {
g := NewCorpseStarchGame(csT(0))
if g.ServitorsUnlocked() || g.ShopUnlocked() || g.SumpUnlocked() || g.MissionsUnlocked() {
t.Fatalf("в начале партии ни один раздел не должен быть открыт")
}
g.TotalEarned = corpseStarchUnlockServitors
if !g.ServitorsUnlocked() {
t.Errorf("сервиторы должны открыться на пороге %v", corpseStarchUnlockServitors)
}
if g.ShopUnlocked() {
t.Errorf("магазин не должен быть открыт раньше своего порога")
}
g.TotalEarned = corpseStarchUnlockMissions
if !g.ShopUnlocked() || !g.SumpUnlocked() || !g.MissionsUnlocked() {
t.Errorf("на пороге зачисток все более ранние разделы тоже должны быть открыты")
}
}
func TestBuyServitorRespectsUnlockAndCost(t *testing.T) {
g := NewCorpseStarchGame(csT(0))
g.Starch = 5
if g.BuyServitor(0) {
t.Fatalf("покупка не должна была пройти при нехватке средств")
}
g.Starch = 10
if !g.BuyServitor(0) {
t.Fatalf("покупка должна была пройти при ровно достаточных средствах")
}
if g.ServitorCounts[0] != 1 {
t.Errorf("счётчик тира 0 должен был увеличиться")
}
if g.Starch != 0 {
t.Errorf("стоимость должна была списаться полностью, получено %v", g.Starch)
}
g.Starch = 1000
if g.BuyServitor(1) {
t.Errorf("тир 1 не должен быть доступен без достаточного TotalEarned")
}
}
func TestServitorCostScalesUp(t *testing.T) {
g := NewCorpseStarchGame(csT(0))
firstCost := g.servitorCost(0)
g.Starch = firstCost
g.BuyServitor(0)
secondCost := g.servitorCost(0)
if secondCost <= firstCost {
t.Errorf("стоимость следующей покупки должна расти, было %v стало %v", firstCost, secondCost)
}
}
func TestBuyClickUpgrade(t *testing.T) {
g := NewCorpseStarchGame(csT(0))
g.Starch = corpseStarchClickUpgradeBaseCost
before := g.ClickYield
if !g.BuyClickUpgrade() {
t.Fatalf("апгрейд должен был пройти при достаточных средствах")
}
if g.ClickYield <= before {
t.Errorf("доход клика должен был вырасти")
}
if g.Starch != 0 {
t.Errorf("стоимость апгрейда должна была списаться полностью")
}
}
func TestDipChainswordBonusOutcome(t *testing.T) {
g := NewCorpseStarchGame(csT(0))
before := g.Starch
outcome := g.DipChainsword(csT(0), 0.1)
if outcome != DipBonusStarch {
t.Fatalf("ожидался исход DipBonusStarch при малом roll, получено %v", outcome)
}
if g.Starch <= before {
t.Errorf("запас должен был вырасти при бонусном исходе")
}
}
func TestDipChainswordBlessingGrantsTemporaryMultiplier(t *testing.T) {
g := NewCorpseStarchGame(csT(0))
outcome := g.DipChainsword(csT(0), 0.6)
if outcome != DipMachineSpiritBlessing {
t.Fatalf("ожидался исход DipMachineSpiritBlessing, получено %v", outcome)
}
if g.currentClickYield(csT(0)) != g.ClickYield*2 {
t.Errorf("во время благословения доход клика должен удваиваться")
}
if g.currentClickYield(csT(31)) != g.ClickYield {
t.Errorf("после истечения 30 секунд бонус должен был закончиться")
}
}
func TestDipChainswordNothingOutcome(t *testing.T) {
g := NewCorpseStarchGame(csT(0))
before := g.Starch
outcome := g.DipChainsword(csT(0), 0.8)
if outcome != DipNothing {
t.Fatalf("ожидался исход DipNothing, получено %v", outcome)
}
if g.Starch != before {
t.Errorf("запас не должен был измениться при пустом исходе")
}
}
func TestDipChainswordCorruptionOutcome(t *testing.T) {
g := NewCorpseStarchGame(csT(0))
g.Starch = 100
outcome := g.DipChainsword(csT(0), 0.95)
if outcome != DipCorruption {
t.Fatalf("ожидался исход DipCorruption, получено %v", outcome)
}
if g.Corruption != 1 {
t.Errorf("скверна должна была увеличиться на 1")
}
if g.Starch >= 100 {
t.Errorf("запас должен был уменьшиться от порчи, получено %v", g.Starch)
}
}
func TestStartMissionRequiresUnlockAndNoActiveMission(t *testing.T) {
g := NewCorpseStarchGame(csT(0))
if g.StartMission(csT(0), 0) {
t.Fatalf("миссия не должна была начаться без открытого порога")
}
g.TotalEarned = corpseStarchUnlockMissions
if !g.StartMission(csT(0), 0) {
t.Fatalf("миссия должна была начаться при открытом пороге")
}
if g.StartMission(csT(1), 1) {
t.Errorf("нельзя начать вторую миссию, пока активна первая")
}
}
func TestMissionRemainingAndCollect(t *testing.T) {
g := NewCorpseStarchGame(csT(0))
g.TotalEarned = corpseStarchUnlockMissions
g.StartMission(csT(0), 0) // "vermin", 20 секунд
if g.MissionRemaining(csT(5)) <= 0 {
t.Fatalf("через 5 секунд миссия ещё не должна была закончиться")
}
if _, ok := g.CollectMission(csT(5), 0.5); ok {
t.Errorf("нельзя забрать награду до завершения миссии")
}
if g.MissionRemaining(csT(25)) != 0 {
t.Errorf("через 25 секунд миссия (20 сек) должна была завершиться")
}
reward, ok := g.CollectMission(csT(25), 0.5)
if !ok {
t.Fatalf("награда должна была быть получена после завершения")
}
def := corpseStarchMissionDefs[0]
wantReward := def.RewardMin + 0.5*(def.RewardMax-def.RewardMin)
if reward != wantReward {
t.Errorf("ожидалась награда %v, получено %v", wantReward, reward)
}
if g.ActiveMission != nil {
t.Errorf("активная миссия должна была сброситься после получения награды")
}
if g.MissionsDone != 1 {
t.Errorf("счётчик завершённых миссий должен был увеличиться")
}
}
func TestLogTrimsToLimit(t *testing.T) {
g := NewCorpseStarchGame(csT(0))
for i := 0; i < corpseStarchLogLimit+5; i++ {
g.addLog("test.key")
}
if len(g.Log) != corpseStarchLogLimit {
t.Errorf("лог должен обрезаться до лимита %d, получено %d", corpseStarchLogLimit, len(g.Log))
}
}