返回 DeepSeek-Reasonix
catalog_budget_test.go
根目录 / internal / skill / catalog_budget_test.go
1 package skill
2
3 import (
4 "fmt"
5 "strings"
6 "testing"
7 "unicode/utf8"
8 )
9
10 func TestCatalogSharesDescriptionBudgetBeforeOmittingSkills(t *testing.T) {
11 var skills []Skill
12 for i := range 60 {
13 skills = append(skills, Skill{
14 Name: fmt.Sprintf("skill-%03d", i), Description: strings.Repeat("description ", 30),
15 })
16 }
17 skills = append(skills, Skill{Name: "private", Invocation: "manual"})
18 out := CatalogBlock(skills)
19 if utf8.RuneCountInString(out) > IndexMaxChars {
20 t.Fatal("catalog exceeded its character budget")
21 }
22 for _, sk := range skills[:60] {
23 if !strings.Contains(out, "- "+sk.Name+" — ") {
24 t.Errorf("missing skill or description: %s", sk.Name)
25 }
26 }
27 if strings.Contains(out, "private") || strings.Contains(out, "more skills") {
28 t.Fatalf("unexpected visibility or overflow: %s", out)
29 }
30 if out != CatalogBlock(skills) || out != ReadOnlyCatalogBlock(skills) {
31 t.Fatal("catalog differs across identical calls or read-only rendering")
32 }
33 }
34
35 func TestCatalogOverflowPreservesWholeEntriesAndReportsOmissions(t *testing.T) {
36 var skills []Skill
37 names := map[string]bool{}
38 for i := range 200 {
39 name := fmt.Sprintf("skill-%03d-%s", i, strings.Repeat("x", 40))
40 names[name] = true
41 skills = append(skills, Skill{Name: name, RunAs: RunSubagent, Description: "A useful operation"})
42 }
43 out := CatalogBlock(skills)
44 if utf8.RuneCountInString(out) > IndexMaxChars || !strings.HasSuffix(out, "\n```") {
45 t.Fatal("overflow broke the catalog budget or envelope")
46 }
47 shown := 0
48 for line := range strings.SplitSeq(out, "\n") {
49 if !strings.HasPrefix(line, "- ") {
50 continue
51 }
52 name, _, _ := strings.Cut(strings.TrimPrefix(line, "- "), " ")
53 if !names[name] || !strings.Contains(line, "[🧬 subagent]") {
54 t.Fatalf("partial skill identity or tag: %q", line)
55 }
56 shown++
57 }
58 if shown == 0 || !strings.Contains(out, fmt.Sprintf("%d more skills", len(skills)-shown)) ||
59 !strings.Contains(out, "use_capability action=search") {
60 t.Fatalf("overflow lacks accurate count/discovery route: %s", out)
61 }
62 }
63
64 func TestCatalogKeepsUnicodeDescriptionsWithinBudget(t *testing.T) {
65 var skills []Skill
66 for i := range 60 {
67 skills = append(skills, Skill{Name: fmt.Sprintf("unicode-%d", i),
68 Description: strings.Repeat("👨‍👩‍👧‍👦中文é ", 80)})
69 }
70 out := CatalogBlock(skills)
71 if !utf8.ValidString(out) || utf8.RuneCountInString(out) > IndexMaxChars {
72 t.Fatal("unicode catalog is invalid or over budget")
73 }
74 for _, sk := range skills {
75 if !strings.Contains(out, "- "+sk.Name+" ") {
76 t.Errorf("lost identity: %s", sk.Name)
77 }
78 }
79 }
80
81 func TestCatalogPolicyDoesNotDependOnDynamicSkills(t *testing.T) {
82 policy := InvocationPolicyBlock()
83 for _, sk := range []Skill{{Name: "alpha", Description: "first"}, {Name: "beta", Description: "second"}} {
84 if got := IndexBlock([]Skill{sk}); got != policy+"\n\n"+CatalogBlock([]Skill{sk}) {
85 t.Fatal("dynamic catalog changed the stable policy boundary")
86 }
87 }
88 }
89
89 lines GO