Files
ttstd-infinite-canvas/backend/internal/skills/skills_seed_test.go
ddcat666 0636cf7c0c feat(skills): 内置技能 - 补齐总纲引用的方法卡与第三方许可声明,升级影策短剧工作流
内置技能包补齐 SKILL.md 名录中引用的 cards/*.md 方法卡,并为改编自开源项目的包附上 THIRD-PARTY-LICENSES.md。影策短剧制作工作流升级到 1.1.0,新增输入分流、故事圣经、状态机与镜头连续性硬门禁。新增测试拦截总纲引用了但包内缺失的方法卡。
2026-09-30 03:42:02 +08:00

101 lines
3.2 KiB
Go
Raw 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 skills
import (
"path/filepath"
"regexp"
"testing"
"infinite-canvas/backend/internal/model"
"infinite-canvas/backend/internal/repository"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
// 总纲名录里写死的 `cards/…` 路径会被 Agent 直接交给 skill_read_file;
// 包里缺卡时只会在运行时报「读取参考资料失败」,所以在这里提前拦住。
func TestBuiltinPackagesShipReferencedCards(t *testing.T) {
packages, err := loadBuiltinSkillPackages(nil)
if err != nil {
t.Fatal(err)
}
// 只认具体文件名;`cards/<slug>.md` 这类占位写法不算引用。
reference := regexp.MustCompile("`(cards/[^`<>\\s]+\\.md)`")
for _, item := range packages {
for _, match := range reference.FindAllStringSubmatch(string(item.archive.Files["SKILL.md"]), -1) {
if _, ok := item.archive.Files[match[1]]; !ok {
t.Errorf("builtin skill %s (%s) references missing %s", item.skill.ID, item.skill.Name, match[1])
}
}
}
}
func TestBuiltinMarkdownPackagesPreserveHistoryAndUserState(t *testing.T) {
db, err := gorm.Open(sqlite.Open(filepath.Join(t.TempDir(), "skills.db")), &gorm.Config{})
if err != nil {
t.Fatal(err)
}
sqlDB, err := db.DB()
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { _ = sqlDB.Close() })
if err := db.AutoMigrate(&model.Skill{}, &model.UserSkillState{}, &model.SkillVersion{}, &model.SkillFile{}, &model.BuiltinSkillTombstone{}, &model.User{}, &model.UserIdentity{}); err != nil {
t.Fatal(err)
}
svc := New(repository.New(db), t.TempDir(), nil)
packages, err := loadBuiltinSkillPackages(nil)
if err != nil {
t.Fatal(err)
}
if err := svc.EnsureBuiltinSkills(); err != nil {
t.Fatal(err)
}
if err := svc.EnsureSkillPackages(); err != nil {
t.Fatal(err)
}
const historyID = "16000000000081"
state := model.UserSkillState{ID: "test-state", UserID: "test-user", SkillID: historyID, Added: true, Liked: true}
if err := db.Create(&state).Error; err != nil {
t.Fatal(err)
}
if err := svc.EnsureBuiltinSkills(); err != nil {
t.Fatal(err)
}
var count int64
if err := db.Model(&model.Skill{}).Count(&count).Error; err != nil {
t.Fatal(err)
}
if count != int64(len(packages)) {
t.Fatalf("builtin skill count = %d, want %d", count, len(packages))
}
var saved model.UserSkillState
if err := db.First(&saved, "id = ?", state.ID).Error; err != nil {
t.Fatal(err)
}
if !saved.Added || !saved.Liked {
t.Fatalf("user state lost: %#v", saved)
}
var skill model.Skill
if err := db.First(&skill, "id = ?", historyID).Error; err != nil {
t.Fatal(err)
}
if skill.CurrentVersionID == "" || skill.FileCount < 1 {
t.Fatalf("history skill package not initialized: %#v", skill)
}
}
func TestBuiltinSkillPackageMetadataParser(t *testing.T) {
body := []byte("---\nname: 测试\ndescription: 描述\nmetadata:\n version: \"1.0.0\"\n tag: drama\n---\n\n正文\n")
metadata, err := parseBuiltinSkillMetadata(body)
if err != nil {
t.Fatal(err)
}
if metadata.Name != "测试" || metadata.Description != "描述" || metadata.Version != "1.0.0" || metadata.Tag != "drama" {
t.Fatalf("metadata = %#v", metadata)
}
if _, err := parseBuiltinSkillMetadata([]byte("# no frontmatter")); err == nil {
t.Fatal("expected missing frontmatter error")
}
}