523 lines
21 KiB
Go
523 lines
21 KiB
Go
package main
|
||
|
||
import (
|
||
"math/rand"
|
||
"testing"
|
||
"time"
|
||
)
|
||
|
||
func TestNewStoryModeStateStartsWithThreeOfEach(t *testing.T) {
|
||
now := time.Now()
|
||
s := NewStoryModeState(StoryDifficultyMedium, now)
|
||
for i := 0; i < int(storyResourceCount); i++ {
|
||
if s.Resources[i] != storyStartingAmount {
|
||
t.Errorf("ресурс %d: ожидалось стартовое количество %d, получено %d", i, storyStartingAmount, s.Resources[i])
|
||
}
|
||
if s.Locked[i] {
|
||
t.Errorf("ресурс %d: ничего не должно быть заперто в начале", i)
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestRecordWinIncrementsResource(t *testing.T) {
|
||
s := NewStoryModeState(StoryDifficultyEasy, time.Now())
|
||
s.RecordWin(StoryResTonk)
|
||
if s.Resources[StoryResTonk] != storyStartingAmount+1 {
|
||
t.Errorf("ожидалось увеличение ресурса Тонка на 1, получено %d", s.Resources[StoryResTonk])
|
||
}
|
||
if s.Resources[StoryResDurak] != storyStartingAmount {
|
||
t.Errorf("ресурс Дурака не должен был измениться, получено %d", s.Resources[StoryResDurak])
|
||
}
|
||
}
|
||
|
||
func TestRecordWinLocksResourceAtTarget(t *testing.T) {
|
||
s := NewStoryModeState(StoryDifficultyEasy, time.Now())
|
||
s.Resources[StoryResCheckers] = StoryTargetCheckers - 1
|
||
s.RecordWin(StoryResCheckers)
|
||
if s.Resources[StoryResCheckers] != StoryTargetCheckers {
|
||
t.Errorf("ожидалось достижение цели %d, получено %d", StoryTargetCheckers, s.Resources[StoryResCheckers])
|
||
}
|
||
if !s.Locked[StoryResCheckers] {
|
||
t.Errorf("ресурс должен был запереться в сейф по достижении цели")
|
||
}
|
||
}
|
||
|
||
func TestRecordWinOnLockedResourceKeepsAccumulating(t *testing.T) {
|
||
s := NewStoryModeState(StoryDifficultyEasy, time.Now())
|
||
s.Resources[StoryResChess] = StoryTargetChess
|
||
s.Locked[StoryResChess] = true
|
||
s.RecordWin(StoryResChess)
|
||
if s.Resources[StoryResChess] != StoryTargetChess+1 {
|
||
t.Errorf("после фиксации ресурс должен был продолжить копиться без ограничения, получено %d", s.Resources[StoryResChess])
|
||
}
|
||
if !s.Locked[StoryResChess] {
|
||
t.Errorf("ресурс должен был остаться зафиксированным")
|
||
}
|
||
}
|
||
|
||
func TestTickNoLongerDecaysResources(t *testing.T) {
|
||
now := time.Now()
|
||
s := NewStoryModeState(StoryDifficultyEasy, now)
|
||
s.Tick(now.Add(10 * 24 * time.Hour)) // 10 суток — раньше это списало бы 10
|
||
if s.Resources[StoryResTonk] != storyStartingAmount {
|
||
t.Errorf("ресурсы больше не должны расходоваться со временем, получено %d, ожидалось %d", s.Resources[StoryResTonk], storyStartingAmount)
|
||
}
|
||
}
|
||
|
||
func TestTickResetsDailyCountersAfterAFullDay(t *testing.T) {
|
||
now := time.Now()
|
||
s := NewStoryModeState(StoryDifficultyEasy, now)
|
||
s.KlondikeWinsToday = 2
|
||
s.DailyGrantsUsed[StoryResChess] = 3
|
||
s.DailyGrantsUsed[StoryResTicTacToe] = 2
|
||
|
||
s.Tick(now.Add(25 * time.Hour)) // чуть больше суток
|
||
|
||
if s.KlondikeWinsToday != 0 {
|
||
t.Errorf("счётчик побед Косынки за день должен был сброситься, получено %d", s.KlondikeWinsToday)
|
||
}
|
||
if s.DailyGrantsUsed[StoryResChess] != 0 || s.DailyGrantsUsed[StoryResTicTacToe] != 0 {
|
||
t.Errorf("счётчики суточных начислений должны были сброситься у всех ресурсов, получено Chess=%d TicTacToe=%d", s.DailyGrantsUsed[StoryResChess], s.DailyGrantsUsed[StoryResTicTacToe])
|
||
}
|
||
}
|
||
|
||
func TestTickDoesNothingBeforeAFullDay(t *testing.T) {
|
||
now := time.Now()
|
||
s := NewStoryModeState(StoryDifficultyEasy, now)
|
||
s.Tick(now.Add(23 * time.Hour))
|
||
if s.Resources[StoryResTonk] != storyStartingAmount {
|
||
t.Errorf("до истечения полных суток расход не должен был случиться, получено %d", s.Resources[StoryResTonk])
|
||
}
|
||
}
|
||
|
||
func TestTickAccumulatesMultipleDaysAtOnce(t *testing.T) {
|
||
now := time.Now()
|
||
s := NewStoryModeState(StoryDifficultyEasy, now)
|
||
s.DailyGrantsUsed[StoryResChess] = 3
|
||
days := s.Tick(now.Add(72 * time.Hour)) // ровно 3 суток
|
||
if days != 3 {
|
||
t.Errorf("ожидалось 3 учтённых суток, получено %d", days)
|
||
}
|
||
if s.DailyGrantsUsed[StoryResChess] != 0 {
|
||
t.Errorf("суточный счётчик должен был сброситься независимо от числа прошедших суток, получено %d", s.DailyGrantsUsed[StoryResChess])
|
||
}
|
||
}
|
||
|
||
func TestAllResourcesLockedFalseUntilEveryOneIsLocked(t *testing.T) {
|
||
s := NewStoryModeState(StoryDifficultyEasy, time.Now())
|
||
if s.AllResourcesLocked() {
|
||
t.Fatalf("в начале не должно быть уже всё заперто")
|
||
}
|
||
for i := 0; i < int(storyResourceCount); i++ {
|
||
s.Locked[i] = true
|
||
}
|
||
if !s.AllResourcesLocked() {
|
||
t.Errorf("после запирания всех ресурсов AllResourcesLocked должен был вернуть true")
|
||
}
|
||
}
|
||
|
||
func TestCompleteMatchesAllResourcesLocked(t *testing.T) {
|
||
s := NewStoryModeState(StoryDifficultyEasy, time.Now())
|
||
if s.Complete() {
|
||
t.Fatalf("сторимод не должен считаться завершённым в начале")
|
||
}
|
||
for i := 0; i < int(storyResourceCount); i++ {
|
||
s.Locked[i] = true
|
||
}
|
||
if !s.Complete() {
|
||
t.Errorf("сторимод должен был считаться завершённым после запирания всех ресурсов")
|
||
}
|
||
}
|
||
|
||
func TestNewStoryModeStateDefaultVitals(t *testing.T) {
|
||
s := NewStoryModeState(StoryDifficultyEasy, time.Now())
|
||
if s.Stress != StoryStressFloor {
|
||
t.Errorf("ожидался стартовый стресс %d, получено %d", StoryStressFloor, s.Stress)
|
||
}
|
||
if s.Poisoning != 0 {
|
||
t.Errorf("ожидалось стартовое отравление 0, получено %d", s.Poisoning)
|
||
}
|
||
if s.ToxinLevel != 0 {
|
||
t.Errorf("ожидался стартовый токсин 0, получено %d", s.ToxinLevel)
|
||
}
|
||
}
|
||
|
||
func TestAwardResourceRespectsDailyLimit(t *testing.T) {
|
||
s := NewStoryModeState(StoryDifficultyEasy, time.Now())
|
||
for i := 0; i < StoryDailyGrantsLimit; i++ {
|
||
if !s.AwardResource(StoryResChess) {
|
||
t.Fatalf("начисление %d должно было пройти (лимит %d)", i+1, StoryDailyGrantsLimit)
|
||
}
|
||
}
|
||
if s.AwardResource(StoryResChess) {
|
||
t.Errorf("начисление сверх дневного лимита не должно было пройти")
|
||
}
|
||
if s.Resources[StoryResChess] != storyStartingAmount+StoryDailyGrantsLimit {
|
||
t.Errorf("ожидалось %d очков ресурса, получено %d", storyStartingAmount+StoryDailyGrantsLimit, s.Resources[StoryResChess])
|
||
}
|
||
}
|
||
|
||
func TestAwardResourceLimitResetsAfterADay(t *testing.T) {
|
||
now := time.Now()
|
||
s := NewStoryModeState(StoryDifficultyEasy, now)
|
||
for i := 0; i < StoryDailyGrantsLimit; i++ {
|
||
s.AwardResource(StoryResChess)
|
||
}
|
||
s.Tick(now.Add(25 * time.Hour))
|
||
if !s.AwardResource(StoryResChess) {
|
||
t.Errorf("после сброса суточного счётчика начисление снова должно было пройти")
|
||
}
|
||
}
|
||
|
||
func TestAwardResourceDailyLimitIsPerResourceNotGlobal(t *testing.T) {
|
||
s := NewStoryModeState(StoryDifficultyEasy, time.Now())
|
||
for i := 0; i < StoryDailyGrantsLimit; i++ {
|
||
if !s.AwardResource(StoryResTicTacToe) {
|
||
t.Fatalf("начисление %d крестикам-ноликам должно было пройти", i+1)
|
||
}
|
||
}
|
||
if s.AwardResource(StoryResTicTacToe) {
|
||
t.Errorf("крестики-нолики должны были исчерпать именно свой лимит")
|
||
}
|
||
// у шашек лимит совершенно свой, не должен быть затронут
|
||
if !s.AwardResource(StoryResCheckers) {
|
||
t.Errorf("исчерпанный лимит крестиков-ноликов не должен был повлиять на лимит шашек")
|
||
}
|
||
}
|
||
|
||
func TestSpendAntidepressantCanGoBelowFloor(t *testing.T) {
|
||
now := time.Now()
|
||
s := NewStoryModeState(StoryDifficultyEasy, now)
|
||
s.Stress = 35
|
||
s.Resources[StoryResKlondike] = 5
|
||
if !s.SpendAntidepressant(now) {
|
||
t.Fatalf("трата антидепрессанта должна была пройти")
|
||
}
|
||
if s.Stress != 15 {
|
||
t.Errorf("ожидался стресс 15 (35-20, ниже обычного пола), получено %d", s.Stress)
|
||
}
|
||
if s.Resources[StoryResKlondike] != 4 {
|
||
t.Errorf("ожидалось списание 1 антидепрессанта, получено %d осталось", s.Resources[StoryResKlondike])
|
||
}
|
||
if !s.StressRecoveryActive {
|
||
t.Errorf("должно было запуститься восстановление стресса — он ниже обычного пола")
|
||
}
|
||
}
|
||
|
||
func TestSpendAntidepressantNeverGoesBelowZero(t *testing.T) {
|
||
now := time.Now()
|
||
s := NewStoryModeState(StoryDifficultyEasy, now)
|
||
s.Stress = 5
|
||
s.Resources[StoryResKlondike] = 5
|
||
s.SpendAntidepressant(now)
|
||
if s.Stress != 0 {
|
||
t.Errorf("стресс не должен был уйти ниже 0, получено %d", s.Stress)
|
||
}
|
||
}
|
||
|
||
func TestSpendAntidepressantFailsWithoutResource(t *testing.T) {
|
||
now := time.Now()
|
||
s := NewStoryModeState(StoryDifficultyEasy, now)
|
||
s.Resources[StoryResKlondike] = 0
|
||
if s.SpendAntidepressant(now) {
|
||
t.Errorf("трата без ресурса не должна была пройти")
|
||
}
|
||
}
|
||
|
||
func TestApplyStressRecoveryReturnsToFloorGradually(t *testing.T) {
|
||
now := time.Now()
|
||
s := NewStoryModeState(StoryDifficultyEasy, now)
|
||
s.Stress = 40
|
||
s.Resources[StoryResKlondike] = 1
|
||
s.SpendAntidepressant(now) // стресс 20 (на полу — восстановление не нужно)
|
||
|
||
s.Stress = 60
|
||
s.Resources[StoryResKlondike] = 1
|
||
s.SpendAntidepressant(now) // стресс 40, всё ещё выше пола — тоже без восстановления
|
||
if s.StressRecoveryActive {
|
||
t.Fatalf("восстановление не должно было запуститься — стресс всё ещё не ниже пола")
|
||
}
|
||
|
||
s.Stress = 25
|
||
s.Resources[StoryResKlondike] = 1
|
||
s.SpendAntidepressant(now) // стресс 5, ниже пола — запускается восстановление
|
||
|
||
s.ApplyStressRecovery(now.Add(30 * time.Minute))
|
||
if s.Stress < 10 || s.Stress > 15 {
|
||
t.Errorf("через полчаса ожидался стресс примерно посередине между 5 и 20, получено %d", s.Stress)
|
||
}
|
||
if !s.StressRecoveryActive {
|
||
t.Errorf("восстановление ещё не должно было завершиться через полчаса")
|
||
}
|
||
}
|
||
|
||
func TestApplyStressRecoveryCompletesAfterAnHour(t *testing.T) {
|
||
now := time.Now()
|
||
s := NewStoryModeState(StoryDifficultyEasy, now)
|
||
s.Stress = 25
|
||
s.Resources[StoryResKlondike] = 1
|
||
s.SpendAntidepressant(now) // стресс 5, ниже пола
|
||
|
||
s.ApplyStressRecovery(now.Add(time.Hour))
|
||
if s.Stress != StoryStressFloor {
|
||
t.Errorf("через час стресс должен был вернуться к полу %d, получено %d", StoryStressFloor, s.Stress)
|
||
}
|
||
if s.StressRecoveryActive {
|
||
t.Errorf("восстановление должно было завершиться (деактивироваться) через час")
|
||
}
|
||
}
|
||
|
||
func TestApplyStressRecoveryDoesNothingWhenInactive(t *testing.T) {
|
||
s := NewStoryModeState(StoryDifficultyEasy, time.Now())
|
||
s.Stress = 20
|
||
s.ApplyStressRecovery(time.Now())
|
||
if s.Stress != 20 {
|
||
t.Errorf("без активного восстановления стресс не должен был измениться, получено %d", s.Stress)
|
||
}
|
||
}
|
||
|
||
func TestSpendAntidoteReducesPoisoningWithFloorZero(t *testing.T) {
|
||
s := NewStoryModeState(StoryDifficultyEasy, time.Now())
|
||
s.Poisoning = 15
|
||
s.Resources[StoryResMinesweeper] = 2
|
||
if !s.SpendAntidote() {
|
||
t.Fatalf("трата антидота должна была пройти")
|
||
}
|
||
if s.Poisoning != 0 {
|
||
t.Errorf("ожидалось отравление 0 (15-20, ограничено полом), получено %d", s.Poisoning)
|
||
}
|
||
}
|
||
|
||
func TestSpendAirFilterMarksUsedToday(t *testing.T) {
|
||
s := NewStoryModeState(StoryDifficultyEasy, time.Now())
|
||
s.Resources[StoryResGo] = 1
|
||
if !s.SpendAirFilter() {
|
||
t.Fatalf("трата фильтра должна была пройти")
|
||
}
|
||
if !s.FilterUsedToday {
|
||
t.Errorf("фильтр должен был отметиться использованным сегодня")
|
||
}
|
||
if s.Resources[StoryResGo] != 0 {
|
||
t.Errorf("фильтр должен был списаться, получено %d", s.Resources[StoryResGo])
|
||
}
|
||
}
|
||
|
||
func TestSpendBatteryStartsAirPurification(t *testing.T) {
|
||
now := time.Now()
|
||
s := NewStoryModeState(StoryDifficultyEasy, now)
|
||
s.Resources[StoryResOneOhOne] = 1
|
||
s.ToxinLevel = 80
|
||
if !s.SpendBattery(now) {
|
||
t.Fatalf("трата батарейки должна была пройти")
|
||
}
|
||
if !s.AirPurificationActive {
|
||
t.Errorf("очистка воздуха должна была запуститься")
|
||
}
|
||
if s.AirPurificationFromLevel != 80 {
|
||
t.Errorf("ожидалось запомненное начальное значение токсина 80, получено %d", s.AirPurificationFromLevel)
|
||
}
|
||
}
|
||
|
||
func TestApplyAirPurificationReducesToxinGradually(t *testing.T) {
|
||
now := time.Now()
|
||
s := NewStoryModeState(StoryDifficultyEasy, now)
|
||
s.Resources[StoryResOneOhOne] = 1
|
||
s.ToxinLevel = 80
|
||
s.SpendBattery(now)
|
||
|
||
s.ApplyAirPurification(now.Add(30 * time.Minute)) // половина часа — примерно половина токсина
|
||
if s.ToxinLevel < 30 || s.ToxinLevel > 50 {
|
||
t.Errorf("через полчаса ожидался токсин примерно в районе 40, получено %d", s.ToxinLevel)
|
||
}
|
||
if !s.AirPurificationActive {
|
||
t.Errorf("очистка ещё не должна была завершиться через полчаса")
|
||
}
|
||
}
|
||
|
||
func TestApplyAirPurificationCompletesAfterAnHour(t *testing.T) {
|
||
now := time.Now()
|
||
s := NewStoryModeState(StoryDifficultyEasy, now)
|
||
s.Resources[StoryResOneOhOne] = 1
|
||
s.ToxinLevel = 80
|
||
s.SpendBattery(now)
|
||
|
||
s.ApplyAirPurification(now.Add(time.Hour))
|
||
if s.ToxinLevel != 0 {
|
||
t.Errorf("через час токсин должен был дойти до 0, получено %d", s.ToxinLevel)
|
||
}
|
||
if s.AirPurificationActive {
|
||
t.Errorf("очистка должна была завершиться (деактивироваться) через час")
|
||
}
|
||
}
|
||
|
||
func TestApplyAirPurificationDoesNothingWhenInactive(t *testing.T) {
|
||
s := NewStoryModeState(StoryDifficultyEasy, time.Now())
|
||
s.ToxinLevel = 50
|
||
s.ApplyAirPurification(time.Now())
|
||
if s.ToxinLevel != 50 {
|
||
t.Errorf("без активной очистки токсин не должен был измениться, получено %d", s.ToxinLevel)
|
||
}
|
||
}
|
||
|
||
func TestSpendResourceUnlocksIfDropsBelowTarget(t *testing.T) {
|
||
s := NewStoryModeState(StoryDifficultyEasy, time.Now())
|
||
s.Resources[StoryResGo] = StoryTargetGo
|
||
s.Locked[StoryResGo] = true
|
||
s.spendResource(StoryResGo, 1)
|
||
if s.Locked[StoryResGo] {
|
||
t.Errorf("ресурс должен был перестать считаться запертым, опустившись ниже цели")
|
||
}
|
||
}
|
||
|
||
func TestSpendResourceKeepsLockedIfStillAtOrAboveTarget(t *testing.T) {
|
||
s := NewStoryModeState(StoryDifficultyEasy, time.Now())
|
||
s.Resources[StoryResGo] = StoryTargetGo + 5
|
||
s.Locked[StoryResGo] = true
|
||
s.spendResource(StoryResGo, 1)
|
||
if !s.Locked[StoryResGo] {
|
||
t.Errorf("ресурс должен был остаться запертым — он всё ещё выше цели")
|
||
}
|
||
}
|
||
|
||
func TestStoryNeurotoxinProbabilityMapping(t *testing.T) {
|
||
cases := []struct {
|
||
days int
|
||
want float64
|
||
}{
|
||
{0, 0},
|
||
{1, 0.5},
|
||
{2, 0.75},
|
||
{3, 1.0},
|
||
{10, 1.0},
|
||
}
|
||
for _, c := range cases {
|
||
if got := storyNeurotoxinProbability(c.days); got != c.want {
|
||
t.Errorf("для %d дней без фильтра ожидалась вероятность %v, получено %v", c.days, c.want, got)
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestStoryDoorKnockProbabilityMapping(t *testing.T) {
|
||
cases := []struct {
|
||
days int
|
||
want float64
|
||
}{
|
||
{0, 0},
|
||
{1, 0.1},
|
||
{2, 0.5},
|
||
{3, 1.0},
|
||
{10, 1.0},
|
||
}
|
||
for _, c := range cases {
|
||
if got := storyDoorKnockProbability(c.days); got != c.want {
|
||
t.Errorf("для %d дней без стука ожидалась вероятность %v, получено %v", c.days, c.want, got)
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestProcessDayEventsNoReleaseWhenFilterUsedToday(t *testing.T) {
|
||
s := NewStoryModeState(StoryDifficultyEasy, time.Now())
|
||
s.FilterUsedToday = true
|
||
s.DaysSinceFilterUsed = 5 // неважно, каким было раньше — фильтр использован сегодня
|
||
rnd := rand.New(rand.NewSource(1))
|
||
s.processDayEvents(rnd)
|
||
if s.DaysSinceFilterUsed != 0 {
|
||
t.Errorf("счётчик дней без фильтра должен был сброситься в 0, получено %d", s.DaysSinceFilterUsed)
|
||
}
|
||
if s.PendingNeurotoxinAlert {
|
||
t.Errorf("выброс не должен был произойти — фильтр использован сегодня")
|
||
}
|
||
if s.FilterUsedToday {
|
||
t.Errorf("флаг 'использован сегодня' должен был сброситься к следующему дню")
|
||
}
|
||
}
|
||
|
||
func TestProcessDayEventsGuaranteedReleaseAfterThreeDays(t *testing.T) {
|
||
s := NewStoryModeState(StoryDifficultyEasy, time.Now())
|
||
s.DaysSinceFilterUsed = 2 // станет 3 после инкремента — гарантированный выброс
|
||
before := s.ToxinLevel
|
||
rnd := rand.New(rand.NewSource(1))
|
||
s.processDayEvents(rnd)
|
||
if !s.PendingNeurotoxinAlert {
|
||
t.Fatalf("на третьи сутки без фильтра выброс должен был произойти гарантированно")
|
||
}
|
||
if s.ToxinLevel <= before {
|
||
t.Errorf("содержание токсина должно было вырасти, получено %d (было %d)", s.ToxinLevel, before)
|
||
}
|
||
increase := s.ToxinLevel - before
|
||
if increase < 10 || increase > 70 {
|
||
t.Errorf("мощность выброса должна была быть в диапазоне 10-70, получено %d", increase)
|
||
}
|
||
}
|
||
|
||
func TestProcessDayEventsNoReleaseOnFirstNeglectedDay(t *testing.T) {
|
||
// вероятность на первый день без фильтра — 50%, а не 0 и не 100%;
|
||
// проверяем хотя бы то, что при вероятности 0 (только что менялся)
|
||
// выброса точно не будет — это уже покрыто выше. Здесь же
|
||
// проверяем, что счётчик корректно увеличивается на 1 при
|
||
// отсутствии использования.
|
||
s := NewStoryModeState(StoryDifficultyEasy, time.Now())
|
||
s.DaysSinceFilterUsed = 0
|
||
s.FilterUsedToday = false
|
||
rnd := rand.New(rand.NewSource(1))
|
||
s.processDayEvents(rnd)
|
||
if s.DaysSinceFilterUsed != 1 {
|
||
t.Errorf("счётчик дней без фильтра должен был увеличиться до 1, получено %d", s.DaysSinceFilterUsed)
|
||
}
|
||
}
|
||
|
||
func TestProcessDayEventsGuaranteedKnockAfterThreeDays(t *testing.T) {
|
||
s := NewStoryModeState(StoryDifficultyEasy, time.Now())
|
||
s.DaysSinceDoorKnock = 2 // станет 3 — гарантированный стук
|
||
s.Stress = 30
|
||
rnd := rand.New(rand.NewSource(1))
|
||
s.processDayEvents(rnd)
|
||
if !s.PendingDoorKnockAlert {
|
||
t.Fatalf("на третьи сутки без стука он должен был произойти гарантированно")
|
||
}
|
||
if s.Stress != 50 {
|
||
t.Errorf("стресс должен был вырасти на 20 (было 30), получено %d", s.Stress)
|
||
}
|
||
if s.DaysSinceDoorKnock != 0 {
|
||
t.Errorf("счётчик дней без стука должен был сброситься, получено %d", s.DaysSinceDoorKnock)
|
||
}
|
||
}
|
||
|
||
func TestProcessDayEventsStressCappedAtHundred(t *testing.T) {
|
||
s := NewStoryModeState(StoryDifficultyEasy, time.Now())
|
||
s.DaysSinceDoorKnock = 2
|
||
s.Stress = 95
|
||
rnd := rand.New(rand.NewSource(1))
|
||
s.processDayEvents(rnd)
|
||
if s.Stress != 100 {
|
||
t.Errorf("стресс не должен был превысить 100, получено %d", s.Stress)
|
||
}
|
||
}
|
||
|
||
func TestProcessDayEventsToxinCappedAtHundred(t *testing.T) {
|
||
s := NewStoryModeState(StoryDifficultyEasy, time.Now())
|
||
s.DaysSinceFilterUsed = 2
|
||
s.ToxinLevel = 90
|
||
rnd := rand.New(rand.NewSource(1))
|
||
s.processDayEvents(rnd)
|
||
if s.ToxinLevel != 100 {
|
||
t.Errorf("токсин не должен был превысить 100, получено %d", s.ToxinLevel)
|
||
}
|
||
}
|
||
|
||
func TestTickProcessesEachDaySeparatelyOverMultipleDays(t *testing.T) {
|
||
now := time.Now()
|
||
s := NewStoryModeState(StoryDifficultyEasy, now)
|
||
// 5 суток без фильтра — на третий и далее день выброс гарантирован,
|
||
// так что хотя бы один точно должен был случиться
|
||
days := s.Tick(now.Add(5 * 24 * time.Hour))
|
||
if days != 5 {
|
||
t.Fatalf("ожидалось 5 учтённых суток, получено %d", days)
|
||
}
|
||
if !s.PendingNeurotoxinAlert {
|
||
t.Errorf("за 5 суток без фильтра выброс должен был произойти хотя бы раз (гарантированно с 3-х суток)")
|
||
}
|
||
if !s.PendingDoorKnockAlert {
|
||
t.Errorf("за 5 суток стук в дверь тоже должен был произойти хотя бы раз (гарантированно с 3-х суток)")
|
||
}
|
||
}
|