go_games_collection/wayfarer_quests_test.go

126 lines
4.9 KiB
Go
Raw Permalink 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"
// TestWayfarerQuestDefsStructuralIntegrity проверяет каждый из
// реальных (не тестовых) квестов на внутреннюю согласованность:
// все NextStep указывают на существующие шаги, все CargoIdx либо -1
// (не используется), либо валидный индекс в WayfarerCommodities, и
// у каждого квеста есть хотя бы один способ дойти до Terminal-выбора
// от стартового шага.
func TestWayfarerQuestDefsStructuralIntegrity(t *testing.T) {
if len(WayfarerQuestDefs) != 8 {
t.Fatalf("ожидалось 8 квестов, получено %d", len(WayfarerQuestDefs))
}
seenKeys := map[string]bool{}
for _, q := range WayfarerQuestDefs {
if q.Key == "" || q.TitleKey == "" || q.BriefKey == "" {
t.Errorf("квест с пустыми обязательными ключами: %+v", q)
}
if seenKeys[q.Key] {
t.Errorf("дублирующийся ключ квеста: %s", q.Key)
}
seenKeys[q.Key] = true
if len(q.Steps) == 0 {
t.Errorf("квест %s: должен иметь хотя бы один шаг", q.Key)
}
reachesTerminal := false
for stepIdx, step := range q.Steps {
if step.TextKey == "" {
t.Errorf("квест %s, шаг %d: пустой TextKey", q.Key, stepIdx)
}
if len(step.Choices) == 0 {
t.Errorf("квест %s, шаг %d: нет ни одного варианта выбора", q.Key, stepIdx)
}
for choiceIdx, c := range step.Choices {
if c.LabelKey == "" {
t.Errorf("квест %s, шаг %d, выбор %d: пустой LabelKey", q.Key, stepIdx, choiceIdx)
}
if c.CargoIdx != -1 && (c.CargoIdx < 0 || c.CargoIdx >= len(WayfarerCommodities)) {
t.Errorf("квест %s, шаг %d, выбор %d: недопустимый CargoIdx %d", q.Key, stepIdx, choiceIdx, c.CargoIdx)
}
if c.Terminal {
if c.ResultKey == "" {
t.Errorf("квест %s, шаг %d, выбор %d: terminal-выбор без ResultKey", q.Key, stepIdx, choiceIdx)
}
reachesTerminal = true
} else {
if c.NextStep < 0 || c.NextStep >= len(q.Steps) {
t.Errorf("квест %s, шаг %d, выбор %d: NextStep %d вне диапазона шагов (0..%d)",
q.Key, stepIdx, choiceIdx, c.NextStep, len(q.Steps)-1)
}
}
}
}
if !reachesTerminal {
t.Errorf("квест %s: ни один выбор во всём квесте не завершает его (нет ни одного Terminal)", q.Key)
}
}
}
// TestWayfarerQuestDefsAllTranslated проверяет, что для каждого
// ключа перевода, используемого в квестах, есть запись в таблице
// translations на обоих языках (это ловит опечатки в ключах и
// забытые переводы).
func TestWayfarerQuestDefsAllTranslated(t *testing.T) {
checkKey := func(key string) {
t.Helper()
if key == "" {
return
}
entry, ok := translations[key]
if !ok {
t.Errorf("отсутствует перевод для ключа %q", key)
return
}
if entry.ru == "" || entry.en == "" {
t.Errorf("перевод для ключа %q неполный: ru=%q en=%q", key, entry.ru, entry.en)
}
}
for _, q := range WayfarerQuestDefs {
checkKey(q.TitleKey)
checkKey(q.BriefKey)
for _, step := range q.Steps {
checkKey(step.TextKey)
for _, c := range step.Choices {
checkKey(c.LabelKey)
checkKey(c.ResultKey)
}
}
}
}
// TestWayfarerQuestDefsPlayableToCompletion проверяет, что каждый
// квест реально проходим от начала до какого-либо Terminal-выбора,
// просто выбирая первый не-terminal вариант на каждом шаге (а если
// таких нет — берёт первый попавшийся) — ловит зависания/бесконечные
// циклы в ручной разметке шагов.
func TestWayfarerQuestDefsPlayableToCompletion(t *testing.T) {
for _, q := range WayfarerQuestDefs {
s := NewWayfarerShip(WayfarerSystemID{})
if err := s.StartQuest(q.Key); err != nil {
t.Fatalf("квест %s: не удалось начать: %v", q.Key, err)
}
const maxSteps = 20
for i := 0; i < maxSteps && s.ActiveQuest != nil; i++ {
step, _ := s.CurrentQuestStep()
choiceIdx := 0
for idx, c := range step.Choices {
if !c.Terminal {
choiceIdx = idx
break
}
}
if _, err := s.ChooseQuestOption(choiceIdx); err != nil {
t.Fatalf("квест %s: неожиданная ошибка выбора на шаге: %v", q.Key, err)
}
}
if s.ActiveQuest != nil {
t.Errorf("квест %s: не завершился за %d шагов (возможен бесконечный цикл)", q.Key, maxSteps)
}
}
}