112 lines
3.0 KiB
Go
112 lines
3.0 KiB
Go
package hooks
|
|
|
|
import (
|
|
"bytes"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestMatchHooks(t *testing.T) {
|
|
set := HookSet{
|
|
"PreToolUse": {
|
|
{Matcher: "", Hooks: []HookConfig{{Command: "all"}}},
|
|
{Matcher: "*", Hooks: []HookConfig{{Command: "star"}}},
|
|
{Matcher: "bash", Hooks: []HookConfig{{Command: "bash-only"}}},
|
|
{Matcher: "write|edit", Hooks: []HookConfig{{Command: "write-or-edit"}}},
|
|
{Matcher: "Edit.*", Hooks: []HookConfig{{Command: "regex-edit"}}},
|
|
},
|
|
"SessionStart": {
|
|
{Matcher: "ignored", Hooks: []HookConfig{{Command: "session"}}},
|
|
},
|
|
}
|
|
|
|
commands := func(hs []HookConfig) []string {
|
|
out := make([]string, len(hs))
|
|
for i, h := range hs {
|
|
out[i] = h.Command
|
|
}
|
|
return out
|
|
}
|
|
|
|
t.Run("bash matches empty, star, exact", func(t *testing.T) {
|
|
got := commands(set.MatchHooks("PreToolUse", "bash", nil))
|
|
want := []string{"all", "star", "bash-only"}
|
|
if strings.Join(got, ",") != strings.Join(want, ",") {
|
|
t.Fatalf("got %v, want %v", got, want)
|
|
}
|
|
})
|
|
|
|
t.Run("write matches multi-value", func(t *testing.T) {
|
|
got := commands(set.MatchHooks("PreToolUse", "write", nil))
|
|
if !contains(got, "write-or-edit") {
|
|
t.Fatalf("expected write-or-edit in %v", got)
|
|
}
|
|
})
|
|
|
|
t.Run("EditFile matches regex not exact", func(t *testing.T) {
|
|
got := commands(set.MatchHooks("PreToolUse", "EditFile", nil))
|
|
if !contains(got, "regex-edit") {
|
|
t.Fatalf("expected regex-edit in %v", got)
|
|
}
|
|
if contains(got, "bash-only") {
|
|
t.Fatalf("did not expect bash-only in %v", got)
|
|
}
|
|
})
|
|
|
|
t.Run("no-tool-name event ignores matcher", func(t *testing.T) {
|
|
got := commands(set.MatchHooks("SessionStart", "", nil))
|
|
want := []string{"session"}
|
|
if strings.Join(got, ",") != strings.Join(want, ",") {
|
|
t.Fatalf("got %v, want %v", got, want)
|
|
}
|
|
})
|
|
|
|
t.Run("unknown event returns nil", func(t *testing.T) {
|
|
if got := set.MatchHooks("Nope", "bash", nil); got != nil {
|
|
t.Fatalf("expected nil, got %v", got)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestMatchHooksInvalidRegexSkipped(t *testing.T) {
|
|
set := HookSet{
|
|
"PreToolUse": {
|
|
{Matcher: "(unterminated", Hooks: []HookConfig{{Command: "bad"}}},
|
|
{Matcher: "bash", Hooks: []HookConfig{{Command: "good"}}},
|
|
},
|
|
}
|
|
var warn bytes.Buffer
|
|
got := set.MatchHooks("PreToolUse", "bash", &warn)
|
|
if len(got) != 1 || got[0].Command != "good" {
|
|
t.Fatalf("expected only good hook, got %v", got)
|
|
}
|
|
if !strings.Contains(warn.String(), "invalid regexp") {
|
|
t.Fatalf("expected regexp warning, got %q", warn.String())
|
|
}
|
|
}
|
|
|
|
func TestMatchHooksSkipsInvalidHook(t *testing.T) {
|
|
set := HookSet{
|
|
"PreToolUse": {
|
|
{Matcher: "*", Hooks: []HookConfig{{Command: ""}, {Command: "ok"}}},
|
|
},
|
|
}
|
|
var warn bytes.Buffer
|
|
got := set.MatchHooks("PreToolUse", "bash", &warn)
|
|
if len(got) != 1 || got[0].Command != "ok" {
|
|
t.Fatalf("expected only ok hook, got %v", got)
|
|
}
|
|
if !strings.Contains(warn.String(), "invalid hook") {
|
|
t.Fatalf("expected invalid-hook warning, got %q", warn.String())
|
|
}
|
|
}
|
|
|
|
func contains(xs []string, s string) bool {
|
|
for _, x := range xs {
|
|
if x == s {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|