first commit

This commit is contained in:
2026-08-14 23:41:57 +08:00
commit 086803a8dd
471 changed files with 91938 additions and 0 deletions
+111
View File
@@ -0,0 +1,111 @@
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
}