package skills import ( "testing" "git.yeij.top/AskaEth/Cyrene_v2/pkg/plugins/sdk" ) // 本文件专测 design/09 §6.2 的 triggers / paths 判定语义(自动激活)。 func TestMatchGlob_表驱动(t *testing.T) { t.Parallel() cases := []struct { pattern string file string want bool }{ {"src/**/*.ts", "src/a.ts", true}, {"src/**/*.ts", "src/a/b.ts", true}, {"src/**/*.ts", "test/a.ts", false}, {"**/*.go", "/repo/internal/x.go", true}, {"*.go", "internal/x.go", true}, // 模式不含 /:额外按文件名匹配 {"*.go", "internal/x.ts", false}, // 扩展名不符 {"internal/*.go", "internal/x.go", true}, {"internal/*.go", "internal/sub/x.go", false}, // * 不跨目录分隔符 {"**", "anything/at/all", true}, {"internal\\x.go", "internal/x.go", true}, // Windows 反斜杠归一 {"", "x.go", false}, {"x.go", "", false}, {"[bad", "x.go", false}, // 语法非法的模式一律 false } for _, tc := range cases { tc := tc t.Run(tc.pattern+"|"+tc.file, func(t *testing.T) { t.Parallel() if got := MatchGlob(tc.pattern, tc.file); got != tc.want { t.Fatalf("MatchGlob(%q, %q) = %v, want %v", tc.pattern, tc.file, got, tc.want) } }) } } func TestMatchPaths_语义(t *testing.T) { t.Parallel() if MatchPaths(nil, []string{"a.go"}) { t.Fatal("未声明 paths 时不该命中") } if MatchPaths([]string{"*.go"}, nil) { t.Fatal("没有工作文件时不该命中") } if !MatchPaths([]string{"*.md", "*.go"}, []string{"notes.txt", "main.go"}) { t.Fatal("任一模式命中任一文件即应命中") } } func TestMatchTriggers_大小写不敏感(t *testing.T) { t.Parallel() if MatchTriggers(nil, "帮我写简报") { t.Fatal("未声明 triggers 时不该命中") } if !MatchTriggers([]string{"简报", " 汇总 "}, "帮我写一份简报") { t.Fatal("触发词应当命中(含去空白)") } if !MatchTriggers([]string{"BRIEF"}, "make a brief") { t.Fatal("触发词应当大小写不敏感") } if MatchTriggers([]string{"简报"}, "") { t.Fatal("空文本不该命中") } } func TestAutoActivates_语义(t *testing.T) { t.Parallel() if AutoActivates(nil, "x", nil) { t.Fatal("nil 技能不该自动激活") } plain := mustSpecSkill(t, "plain", "d", "", sdk.InvocationBoth) if AutoActivates(plain, "简报", []string{"x.go"}) { t.Fatal("未声明 triggers/paths 时不该自动激活(只能显式调用)") } triggered := mustTriggerSkill(t, "t", []string{"简报"}, nil) if !AutoActivates(triggered, "给我一份简报", nil) { t.Fatal("触发词命中即应自动激活") } if AutoActivates(triggered, "无关的话", nil) { t.Fatal("触发词没命中时不该自动激活") } pathed := mustTriggerSkill(t, "p", nil, []string{"src/**/*.go"}) if !AutoActivates(pathed, "", []string{"src/a/b.go"}) { t.Fatal("paths 命中即应自动激活") } if AutoActivates(pathed, "", []string{"docs/a.md"}) { t.Fatal("paths 没命中时不该自动激活") } } func mustTriggerSkill(t *testing.T, name string, triggers, paths []string) *Skill { t.Helper() skill, err := New(name, "d", "p", nil, nil, nil, WithSpec(Spec{Triggers: triggers, Paths: paths})) if err != nil { t.Fatalf("New(%s): %v", name, err) } return skill }