| 1 | package doctor |
| 2 | |
| 3 | import ( |
| 4 | "strings" |
| 5 | "testing" |
| 6 | |
| 7 | "reasonix/internal/config" |
| 8 | "reasonix/internal/skill" |
| 9 | ) |
| 10 | |
| 11 | func TestCollectSkillHealthWarnings(t *testing.T) { |
| 12 | off := false |
| 13 | warns := CollectSkillHealthWarnings(SkillHealthOptions{ |
| 14 | Skills: []skill.Skill{ |
| 15 | {Name: "empty", Description: ""}, |
| 16 | {Name: "typo-profile", Description: "ok", InvalidProfiles: []string{"deliverx"}}, |
| 17 | { |
| 18 | Name: "conflict", |
| 19 | Description: "ok", |
| 20 | Triggers: []string{"review"}, |
| 21 | NegativeTriggers: []string{"review"}, |
| 22 | AutoUse: "require", |
| 23 | Requires: []string{"mcp-server:github"}, |
| 24 | }, |
| 25 | { |
| 26 | Name: "dup-a", |
| 27 | Description: "ok", |
| 28 | Triggers: []string{"ship it"}, |
| 29 | AutoUse: "require", |
| 30 | }, |
| 31 | { |
| 32 | Name: "dup-b", |
| 33 | Description: "ok", |
| 34 | Triggers: []string{"ship it"}, |
| 35 | AutoUse: "require", |
| 36 | }, |
| 37 | }, |
| 38 | Plugins: []config.PluginEntry{ |
| 39 | {Name: "other", AutoStart: &off}, |
| 40 | }, |
| 41 | FailedServers: map[string]string{"broken": "spawn failed"}, |
| 42 | CacheMismatch: []string{"stale"}, |
| 43 | }) |
| 44 | joined := strings.Join(warns, "\n") |
| 45 | for _, want := range []string{ |
| 46 | `skill "empty" has a missing or placeholder description`, |
| 47 | `skill "conflict" trigger "review" also appears in negative-triggers`, |
| 48 | `skill "conflict" requires mcp-server:github but that MCP server is not configured`, |
| 49 | `multiple require skills share identical triggers`, |
| 50 | `MCP server "broken" is in a host-failed state`, |
| 51 | `MCP server "stale" schema cache fingerprint mismatched`, |
| 52 | `skill "typo-profile" has illegal profiles value "deliverx"`, |
| 53 | } { |
| 54 | if !strings.Contains(joined, want) { |
| 55 | t.Fatalf("warnings missing %q:\n%s", want, joined) |
| 56 | } |
| 57 | } |
| 58 | } |
| 59 |