1package skills
2
3import (
4 "path/filepath"
5 "strings"
6 "testing"
7)
8
9func TestPinsResolveUnionAndMissing(t *testing.T) {
10 a := &Skill{Name: "a", Body: "first"}
11 b := &Skill{Name: "ext:b", Body: "second", DisableModelInvocation: true}
12 pins := Pins{Global: []string{"ext:b", "a", "missing"}, Project: []string{"a", "ext:b"}}
13 selected, warnings := pins.Resolve([]*Skill{b, a})
14 if len(selected) != 2 || selected[0] != a || selected[1] != b {
15 t.Fatalf("selected = %#v", selected)
16 }
17 if len(warnings) != 1 || !strings.Contains(warnings[0], "missing") {
18 t.Fatalf("warnings = %v", warnings)
19 }
20}
21
22func TestPreloadPromptPreservesSkillLocationAndRequest(t *testing.T) {
23 s := &Skill{Name: "review", Body: "Inspect carefully.", Path: filepath.Join("skills", "review", "SKILL.md")}
24 got := PreloadPrompt([]*Skill{s}, "my request")
25 for _, want := range []string{"# Skill: review", "Inspect carefully.", "Skill directory: " + filepath.Dir(s.Path), "User request:\nmy request"} {
26 if !strings.Contains(got, want) {
27 t.Errorf("missing %q in %q", want, got)
28 }
29 }
30 if got := PreloadPrompt(nil, "unchanged"); got != "unchanged" {
31 t.Fatal(got)
32 }
33}
34
35func TestPinsResolveDeduplicatesAliasAndCanonical(t *testing.T) {
36 inner := &Skill{Name: "golang-patterns", Aliases: []string{"systems/subskills/golang-patterns"}, Path: "/r/systems/subskills/golang-patterns/SKILL.md"}
37 other := &Skill{Name: "alpha", Path: "/r/alpha/SKILL.md"}
38 pins := Pins{
39 Global: []string{"systems/subskills/golang-patterns", "alpha"},
40 Project: []string{"golang-patterns"},
41 }
42 available := []*Skill{inner, other}
43 for i := 0; i < 20; i++ { // map iteration must not affect the result
44 selected, warnings := pins.Resolve(available)
45 if len(warnings) != 0 || len(selected) != 2 || selected[0] != other || selected[1] != inner {
46 t.Fatalf("selected=%v warnings=%v", selected, warnings)
47 }
48 }
49 project, global := pins.Scopes(available, inner)
50 if !project || !global {
51 t.Fatalf("scopes = project %v global %v", project, global)
52 }
53 project, global = pins.Scopes(available, other)
54 if project || !global {
55 t.Fatalf("scopes = project %v global %v", project, global)
56 }
57}