Files
ttstd-infinite-canvas/backend/internal/skills/skills_presets_test.go
T

110 lines
4.8 KiB
Go

package skills
import (
"strings"
"testing"
)
func TestSkillPresetsCatalogIsValid(t *testing.T) {
svc := New(nil, "", nil)
presets, err := svc.SkillPresets()
if err != nil {
t.Fatal(err)
}
if len(presets) == 0 {
t.Fatal("场景预设目录不能为空")
}
seeded := make(map[string]struct{}, 128)
seedIDs, err := builtinSeedSkillIDs()
if err != nil {
t.Fatal(err)
}
for _, id := range seedIDs {
seeded[id] = struct{}{}
}
if len(seeded) == 0 {
t.Fatal("内置种子技能为空,对账失去意义")
}
seen := map[string]struct{}{}
for _, preset := range presets {
if _, dup := seen[preset.PresetID]; dup {
t.Fatalf("presetId 重复: %s", preset.PresetID)
}
seen[preset.PresetID] = struct{}{}
if len(preset.SkillIDs) == 0 || len(preset.SkillIDs) > 8 {
t.Fatalf("%s 技能数 %d 超出 1-8", preset.PresetID, len(preset.SkillIDs))
}
for _, skillID := range preset.SkillIDs {
// v1 硬约束:preset 只允许引用种子市场已上架技能。
if _, ok := seeded[skillID]; !ok {
t.Fatalf("%s 引用未上架技能 %s", preset.PresetID, skillID)
}
}
if preset.Rationale == "" {
t.Fatalf("%s 缺推荐理由", preset.PresetID)
}
}
}
func TestSkillPresetsRejectUnseededSkillReference(t *testing.T) {
// 防回归:preset 引用一个不在种子清单里的 skillId 时必须被校验拦下,
// 否则用户一键挂载会遇到装不上的技能(v1 明确禁止)。
original := builtinSkillPresetsJSON
defer func() { builtinSkillPresetsJSON = original }()
builtinSkillPresetsJSON = []byte(`{"version":1,"presets":[{"presetId":"bad","name":"坏预设","scene":"drama","skillIds":["16000000000099","99999999999999"],"rationale":"引用了不存在的技能","source":"hand-curated","evidence":"E4","upgrade":""}]}`)
svc := New(nil, "", nil)
if _, err := svc.SkillPresets(); err == nil || !strings.Contains(err.Error(), "未上架技能") {
t.Fatalf("应拒绝未上架技能引用,实际: %v", err)
}
}
func TestSkillPresetsRejectInvalidSkillSeed(t *testing.T) {
original := builtinSkillsJSON
defer func() { builtinSkillsJSON = original }()
builtinSkillsJSON = []byte(`not-json`)
if _, err := New(nil, "", nil).SkillPresets(); err == nil || !strings.Contains(err.Error(), "解析内置技能失败") {
t.Fatalf("应明确报告内置技能种子损坏,实际: %v", err)
}
}
func TestSkillPresetsIgnoreDisabledOrPrivateSeeds(t *testing.T) {
original := builtinSkillsJSON
defer func() { builtinSkillsJSON = original }()
builtinSkillsJSON = []byte(`[
{"skill_id":"enabled-public","status":1,"is_private":false},
{"skill_id":"disabled-public","status":0,"is_private":false},
{"skill_id":"enabled-private","status":1,"is_private":true}
]`)
originalPresets := builtinSkillPresetsJSON
defer func() { builtinSkillPresetsJSON = originalPresets }()
builtinSkillPresetsJSON = []byte(`{"version":1,"presets":[{"presetId":"ok","name":"可用预设","scene":"drama","skillIds":["enabled-public"],"rationale":"只引用公开启用技能","source":"hand-curated","evidence":"E4","upgrade":""}]}`)
if _, err := New(nil, "", nil).SkillPresets(); err != nil {
t.Fatalf("公开启用种子应可被预设引用: %v", err)
}
for _, skillID := range []string{"disabled-public", "enabled-private"} {
builtinSkillPresetsJSON = []byte(`{"version":1,"presets":[{"presetId":"bad","name":"非法预设","scene":"drama","skillIds":["` + skillID + `"],"rationale":"不应通过校验","source":"hand-curated","evidence":"E4","upgrade":""}]}`)
if _, err := New(nil, "", nil).SkillPresets(); err == nil || !strings.Contains(err.Error(), "未上架技能") {
t.Fatalf("%s 不应被视为已上架,实际: %v", skillID, err)
}
}
}
func TestSkillPresetsRejectOverBudgetAndTelemetrySource(t *testing.T) {
original := builtinSkillPresetsJSON
defer func() { builtinSkillPresetsJSON = original }()
// 超过 8 个激活位必须被拒(影策每轮最多激活 8 个技能)。
builtinSkillPresetsJSON = []byte(`{"version":1,"presets":[{"presetId":"big","name":"超大预设","scene":"drama","skillIds":["a","b","c","d","e","f","g","h","i"],"rationale":"超预算","source":"hand-curated","evidence":"E4","upgrade":""}]}`)
svc := New(nil, "", nil)
if _, err := svc.SkillPresets(); err == nil || !strings.Contains(err.Error(), "1-8") {
t.Fatalf("应拒绝超 8 技能预设,实际: %v", err)
}
// v1 只允许手工策展:遥测驱动的预设要等 #590 有数据后才放开。
builtinSkillPresetsJSON = []byte(`{"version":1,"presets":[{"presetId":"tele","name":"遥测预设","scene":"drama","skillIds":["16000000000099"],"rationale":"数据驱动","source":"telemetry","evidence":"E4","upgrade":""}]}`)
if _, err := svc.SkillPresets(); err == nil || !strings.Contains(err.Error(), "hand-curated") {
t.Fatalf("应拒绝非手工策展来源,实际: %v", err)
}
}