Сборки нередко раздают только пресет одиночной игры. Внутри это плоский список «Параметр=значение» с точками вместо вложенности, поэтому значения переносятся в SandboxVars.lua профиля по одному: комментарии игры и порядок остаются на месте, а параметры модов, которых в файле ещё нет, пропускаются со счётом. Если файла нет вовсе, он собирается из пресета целиком. Заодно панель принимает строку из игровой кнопки «Поделиться» («Название:ModA;ModB;…»): она заменяет список включённых модов, сохраняя порядок загрузки. Идентификаторов мастерской в такой строке нет, поэтому пакеты добавляются только для модов, чьи файлы уже на диске, а про остальные панель предупреждает. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
117 lines
3.9 KiB
Go
117 lines
3.9 KiB
Go
package preset
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/mrleo1nid/pzmanager/internal/pzconfig"
|
|
)
|
|
|
|
// sandboxCFG повторяет то, как пресет выглядит у игры: комментарии с решёткой,
|
|
// расшифровки значений со знаком равенства внутри и точки вместо вложенности.
|
|
const sandboxCFG = `Version=6
|
|
# Changing this also sets the "Population Multiplier" in Advanced Zombie Options. Default = Normal
|
|
-- 1 = Insane
|
|
-- 4 = Normal
|
|
Zombies=4
|
|
|
|
# Controls whether some randomization is applied.
|
|
ZombieVoronoiNoise=true
|
|
DayLength=3
|
|
XpMultiplier=1.5
|
|
StatsDecrease=3
|
|
Temperature=3
|
|
Rain=3
|
|
LootRespawn=1
|
|
FoodRotSpeed=5
|
|
Nutrition=true
|
|
WorldItemRemovalList=Base.Hat, Base.Glasses
|
|
ZombieLore.Speed=2
|
|
ZombieLore.Strength=2
|
|
KDOT.SpecialVehicleChance=4.0
|
|
`
|
|
|
|
func TestParseSandboxPreset(t *testing.T) {
|
|
p := ParseSandboxPreset([]byte(sandboxCFG))
|
|
|
|
if p.Version != "6" {
|
|
t.Errorf("версия = %q", p.Version)
|
|
}
|
|
// Строки «-- 4 = Normal» тоже содержат знак равенства, и параметрами они
|
|
// не являются.
|
|
for key := range p.Values {
|
|
if !sandboxKeyRe.MatchString(key) {
|
|
t.Errorf("в значения попал мусор: %q", key)
|
|
}
|
|
}
|
|
|
|
want := map[string]string{
|
|
"Zombies": "4",
|
|
"ZombieVoronoiNoise": "true",
|
|
"XpMultiplier": "1.5",
|
|
"ZombieLore.Speed": "2",
|
|
"KDOT.SpecialVehicleChance": "4.0",
|
|
"WorldItemRemovalList": `"Base.Hat, Base.Glasses"`,
|
|
}
|
|
for key, value := range want {
|
|
if got := p.Values[key]; got != value {
|
|
t.Errorf("%s = %q, ожидалось %q", key, got, value)
|
|
}
|
|
}
|
|
if _, ok := p.Values["Version"]; ok {
|
|
t.Error("Version не должен попадать в значения: у файла сервера свой VERSION")
|
|
}
|
|
}
|
|
|
|
// Сгенерированный файл читает и сама игра, и парсер панели — второе проверить
|
|
// можно прямо здесь.
|
|
func TestSandboxPresetLuaRoundTrip(t *testing.T) {
|
|
p := ParseSandboxPreset([]byte(sandboxCFG))
|
|
lua := p.Lua()
|
|
|
|
parsed := pzconfig.ParseSandbox(lua)
|
|
if got, ok := parsed.Get("VERSION"); !ok || got != "6" {
|
|
t.Errorf("VERSION = %q (%v)", got, ok)
|
|
}
|
|
for key, want := range p.Values {
|
|
got, ok := parsed.Get(key)
|
|
if !ok {
|
|
t.Errorf("параметр %s не читается обратно:\n%s", key, lua)
|
|
continue
|
|
}
|
|
if got != want {
|
|
t.Errorf("%s = %q, ожидалось %q", key, got, want)
|
|
}
|
|
}
|
|
// Вложенность должна быть настоящей: «ZombieLore.Speed = 2» внутри таблицы
|
|
// Lua не примет.
|
|
if strings.Contains(string(lua), "ZombieLore.Speed =") {
|
|
t.Errorf("точка осталась в имени параметра:\n%s", lua)
|
|
}
|
|
}
|
|
|
|
// Пути бывают глубже одного уровня — файл должен остаться разбираемым.
|
|
func TestSandboxPresetDeepPath(t *testing.T) {
|
|
p := ParseSandboxPreset([]byte("A.B.C=7\nZombies=1\nDayLength=3\nRain=2\n"))
|
|
parsed := pzconfig.ParseSandbox(p.Lua())
|
|
if got, ok := parsed.Get("A.B.C"); !ok || got != "7" {
|
|
t.Fatalf("A.B.C = %q (%v)\n%s", got, ok, p.Lua())
|
|
}
|
|
}
|
|
|
|
func TestLooksLikeSandboxPreset(t *testing.T) {
|
|
if !looksLikeSandboxPreset([]byte(sandboxCFG)) {
|
|
t.Error("пресет песочницы не опознан")
|
|
}
|
|
// В том же архиве лежат списки модов и настройки папок с тем же
|
|
// расширением .cfg.
|
|
modFolders := "version=2\nnext=15\nfolder=3|1|4D,61,70,73\n"
|
|
if looksLikeSandboxPreset([]byte(modFolders)) {
|
|
t.Error("настройки папок приняты за пресет песочницы")
|
|
}
|
|
modList := "!fav!:\nSophie-42-v2:ModA;ModB;ModC\n"
|
|
if looksLikeSandboxPreset([]byte(modList)) {
|
|
t.Error("список модов принят за пресет песочницы")
|
|
}
|
|
}
|