package main import "testing" // withTestQuest временно подменяет WayfarerQuestDefs на один // тестовый квест с двумя шагами и восстанавливает оригинал по // завершении теста. func withTestQuest(t *testing.T) { t.Helper() original := WayfarerQuestDefs WayfarerQuestDefs = []WayfarerQuestDef{ { Key: "test.quest", TitleKey: "test.title", BriefKey: "test.brief", Steps: []WayfarerQuestStep{ { TextKey: "test.step0", Choices: []WayfarerQuestChoice{ {LabelKey: "test.choice.a", NextStep: 1}, {LabelKey: "test.choice.b", Terminal: true, Success: false, CreditsDelta: -50}, }, }, { TextKey: "test.step1", Choices: []WayfarerQuestChoice{ {LabelKey: "test.choice.c", Terminal: true, Success: true, CreditsDelta: 500, HullDelta: -10}, }, }, }, }, } t.Cleanup(func() { WayfarerQuestDefs = original }) } func TestStartQuestSetsActiveState(t *testing.T) { withTestQuest(t) s := NewWayfarerShip(WayfarerSystemID{}) if err := s.StartQuest("test.quest"); err != nil { t.Fatalf("неожиданная ошибка старта квеста: %v", err) } if s.ActiveQuest == nil || s.ActiveQuest.Key != "test.quest" || s.ActiveQuest.Step != 0 { t.Fatalf("ожидалось активное состояние квеста на шаге 0, получено: %+v", s.ActiveQuest) } } func TestCannotStartQuestWhileAnotherActive(t *testing.T) { withTestQuest(t) s := NewWayfarerShip(WayfarerSystemID{}) s.StartQuest("test.quest") if err := s.StartQuest("test.quest"); err != errWayfarerQuestAlreadyActive { t.Errorf("ожидалась ошибка уже активного квеста, получено: %v", err) } } func TestCannotStartUnknownQuest(t *testing.T) { withTestQuest(t) s := NewWayfarerShip(WayfarerSystemID{}) if err := s.StartQuest("no.such.quest"); err != errWayfarerQuestNotFound { t.Errorf("ожидалась ошибка ненайденного квеста, получено: %v", err) } } func TestChooseQuestOptionAdvancesToNextStep(t *testing.T) { withTestQuest(t) s := NewWayfarerShip(WayfarerSystemID{}) s.StartQuest("test.quest") choice, err := s.ChooseQuestOption(0) // "a" -> шаг 1 if err != nil { t.Fatalf("неожиданная ошибка выбора: %v", err) } if choice.LabelKey != "test.choice.a" { t.Errorf("ожидался выбор 'a', получено %s", choice.LabelKey) } if s.ActiveQuest == nil || s.ActiveQuest.Step != 1 { t.Fatalf("ожидался переход на шаг 1, получено: %+v", s.ActiveQuest) } step, ok := s.CurrentQuestStep() if !ok || step.TextKey != "test.step1" { t.Fatalf("ожидался текст шага 1, получено: %+v", step) } } func TestChooseTerminalChoiceEndsQuestSuccessfully(t *testing.T) { withTestQuest(t) s := NewWayfarerShip(WayfarerSystemID{}) s.StartQuest("test.quest") s.ChooseQuestOption(0) // на шаг 1 before := s.Credits beforeHull := s.Hull if _, err := s.ChooseQuestOption(0); err != nil { // "c" -> успешное завершение t.Fatalf("неожиданная ошибка: %v", err) } if s.ActiveQuest != nil { t.Errorf("активный квест должен был сброситься после завершения") } if !s.CompletedQuests["test.quest"] { t.Errorf("квест должен был отметиться как завершённый успешно") } if s.Credits != before+500 { t.Errorf("ожидалось начисление 500 кредитов, получено %v (было %v)", s.Credits, before) } if s.Hull != beforeHull-10 { t.Errorf("ожидалось повреждение корпуса на 10, получено %d (было %d)", s.Hull, beforeHull) } } func TestChooseTerminalChoiceCanEndQuestInFailure(t *testing.T) { withTestQuest(t) s := NewWayfarerShip(WayfarerSystemID{}) s.StartQuest("test.quest") before := s.Credits if _, err := s.ChooseQuestOption(1); err != nil { // "b" -> немедленный провал t.Fatalf("неожиданная ошибка: %v", err) } if s.ActiveQuest != nil { t.Errorf("активный квест должен был сброситься после провала") } if !s.FailedQuests["test.quest"] { t.Errorf("квест должен был отметиться как провальный") } if s.Credits != before-50 { t.Errorf("ожидалось списание 50 кредитов, получено %v (было %v)", s.Credits, before) } } func TestCannotRestartCompletedQuest(t *testing.T) { withTestQuest(t) s := NewWayfarerShip(WayfarerSystemID{}) s.StartQuest("test.quest") s.ChooseQuestOption(0) s.ChooseQuestOption(0) if err := s.StartQuest("test.quest"); err != errWayfarerQuestAlreadyDone { t.Errorf("ожидалась ошибка уже завершённого квеста, получено: %v", err) } } func TestChooseQuestOptionInvalidIndex(t *testing.T) { withTestQuest(t) s := NewWayfarerShip(WayfarerSystemID{}) s.StartQuest("test.quest") if _, err := s.ChooseQuestOption(99); err != errWayfarerInvalidChoice { t.Errorf("ожидалась ошибка недопустимого выбора, получено: %v", err) } } func TestChooseQuestOptionWithNoActiveQuest(t *testing.T) { withTestQuest(t) s := NewWayfarerShip(WayfarerSystemID{}) if _, err := s.ChooseQuestOption(0); err != errWayfarerNoActiveQuest { t.Errorf("ожидалась ошибка отсутствия активного квеста, получено: %v", err) } } func TestAbandonQuestAllowsRestartLater(t *testing.T) { withTestQuest(t) s := NewWayfarerShip(WayfarerSystemID{}) s.StartQuest("test.quest") s.AbandonQuest() if s.ActiveQuest != nil { t.Errorf("активный квест должен был обнулиться после отказа") } if err := s.StartQuest("test.quest"); err != nil { t.Errorf("после отказа квест должен быть доступен для повторного старта, получено: %v", err) } } func TestQuestCreditsAndCargoNeverGoNegative(t *testing.T) { withTestQuest(t) s := NewWayfarerShip(WayfarerSystemID{}) s.Credits = 10 s.StartQuest("test.quest") s.ChooseQuestOption(1) // -50 кредитов при балансе 10 if s.Credits < 0 { t.Errorf("кредиты не должны уходить в минус, получено %v", s.Credits) } }