返回 DeepSeek-Reasonix
reasonix_guide_test.go
根目录 / internal / skill / reasonix_guide_test.go
1 package skill_test
2
3 import (
4 "strings"
5 "testing"
6
7 "reasonix/internal/skill"
8 )
9
10 func TestReasonixGuideBuiltinRegistered(t *testing.T) {
11 store := skill.New(skill.Options{HomeDir: t.TempDir(), DisableBuiltins: false})
12 sk, ok := store.Read("reasonix-guide")
13 if !ok {
14 t.Fatal("reasonix-guide must be registered as a builtin")
15 }
16 if sk.Scope != skill.ScopeBuiltin {
17 t.Fatalf("scope = %s", sk.Scope)
18 }
19 if sk.RunAs != skill.RunInline {
20 t.Fatalf("runAs = %s", sk.RunAs)
21 }
22 if sk.Description == "" {
23 t.Fatal("description required for index line")
24 }
25 if !strings.Contains(sk.Body, "doctor capabilities") {
26 t.Fatal("body missing doctor capabilities guidance")
27 }
28 }
29
30 func TestReasonixGuideIndexLineOnly(t *testing.T) {
31 store := skill.New(skill.Options{HomeDir: t.TempDir()})
32 list := store.List()
33 var guide skill.Skill
34 found := false
35 for _, s := range list {
36 if s.Name == "reasonix-guide" {
37 guide = s
38 found = true
39 break
40 }
41 }
42 if !found {
43 t.Fatal("reasonix-guide missing from List")
44 }
45 idx := skill.IndexBlock(list)
46 if !strings.Contains(idx, "reasonix-guide") {
47 t.Fatal("index missing reasonix-guide line")
48 }
49 // Body must not appear in the index block.
50 if strings.Contains(idx, "First action") || strings.Contains(idx, skBodySnippet(guide)) {
51 t.Fatal("skill body leaked into system-prompt index")
52 }
53 // Exactly one index line for the skill name.
54 if c := strings.Count(idx, "- reasonix-guide"); c != 1 {
55 t.Fatalf("index lines for reasonix-guide = %d, want 1", c)
56 }
57 }
58
59 func skBodySnippet(sk skill.Skill) string {
60 body := strings.TrimSpace(sk.Body)
61 if len(body) > 40 {
62 return body[:40]
63 }
64 return body
65 }
66
67 func TestReasonixGuideOverriddenByProject(t *testing.T) {
68 home := t.TempDir()
69 root := t.TempDir()
70 store := skill.New(skill.Options{HomeDir: home, ProjectRoot: root})
71 // Create project override.
72 path, err := store.CreateWithContent("reasonix-guide", skill.ScopeProject, "---\ndescription: override\nrunAs: inline\n---\nproject body\n")
73 if err != nil {
74 t.Fatal(err)
75 }
76 _ = path
77 store2 := skill.New(skill.Options{HomeDir: home, ProjectRoot: root})
78 sk, ok := store2.Read("reasonix-guide")
79 if !ok {
80 t.Fatal("expected override")
81 }
82 if sk.Scope != skill.ScopeProject {
83 t.Fatalf("scope = %s, want project", sk.Scope)
84 }
85 if !strings.Contains(sk.Body, "project body") {
86 t.Fatalf("body = %q", sk.Body)
87 }
88 }
89
90 func TestReasonixGuideDisabled(t *testing.T) {
91 store := skill.New(skill.Options{
92 HomeDir: t.TempDir(),
93 DisabledNames: []string{"reasonix-guide"},
94 })
95 if _, ok := store.Read("reasonix-guide"); ok {
96 t.Fatal("disabled builtin should not be readable")
97 }
98 for _, s := range store.List() {
99 if s.Name == "reasonix-guide" {
100 t.Fatal("disabled builtin should not be listed")
101 }
102 }
103 }
104
105 func TestReasonixGuideIndexStableAcrossCalls(t *testing.T) {
106 store := skill.New(skill.Options{HomeDir: t.TempDir()})
107 a := skill.IndexBlock(store.List())
108 b := skill.IndexBlock(store.List())
109 if a != b {
110 t.Fatal("skills index not byte-stable across List calls")
111 }
112 }
113
113 lines GO