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
+130
View File
@@ -0,0 +1,130 @@
package hooks
import (
"context"
"encoding/json"
"os"
"path/filepath"
"runtime"
"strings"
"testing"
"time"
)
func TestRunnerRunStdinAndEnv(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("sh -c not available on windows")
}
dir := t.TempDir()
outFile := filepath.Join(dir, "captured.json")
envFile := filepath.Join(dir, "env.txt")
r := &Runner{ProjectDir: dir}
h := HookConfig{Command: "cat > " + outFile + "; printf '%s\\n%s\\n%s\\n' \"$PIGO_SESSION_ID\" \"$PIGO_PROJECT_DIR\" \"$PIGO_EVENT_TYPE\" > " + envFile}
input := HookInput{EventType: "PreToolUse", SessionID: "sess-1", ProjectDir: dir, ToolName: "bash"}
if _, err := r.Run(context.Background(), h, input); err != nil {
t.Fatalf("Run() error: %v", err)
}
data, err := os.ReadFile(outFile)
if err != nil {
t.Fatalf("read captured stdin: %v", err)
}
var got HookInput
if err := json.Unmarshal(data, &got); err != nil {
t.Fatalf("stdin was not valid JSON: %v (%s)", err, data)
}
if got.EventType != "PreToolUse" || got.SessionID != "sess-1" || got.ToolName != "bash" {
t.Fatalf("unexpected decoded stdin: %+v", got)
}
envData, _ := os.ReadFile(envFile)
lines := strings.Split(strings.TrimSpace(string(envData)), "\n")
if len(lines) != 3 || lines[0] != "sess-1" || lines[1] != dir || lines[2] != "PreToolUse" {
t.Fatalf("unexpected env: %v", lines)
}
}
func TestRunnerExitCodes(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("sh -c not available on windows")
}
dir := t.TempDir()
r := &Runner{ProjectDir: dir}
ctx := context.Background()
t.Run("exit 0 with json", func(t *testing.T) {
out, err := r.Run(ctx, HookConfig{Command: `echo '{"additionalContext":"hi"}'`}, HookInput{})
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
if out.AdditionalContext != "hi" {
t.Fatalf("unexpected out: %+v", out)
}
})
t.Run("exit 0 non-json is no-op", func(t *testing.T) {
out, err := r.Run(ctx, HookConfig{Command: `echo hello world`}, HookInput{})
if err != nil || out.blocks() || out.AdditionalContext != "" {
t.Fatalf("expected no-op, got out=%+v err=%v", out, err)
}
})
t.Run("exit 2 blocks with stderr reason", func(t *testing.T) {
out, err := r.Run(ctx, HookConfig{Command: `echo "denied" >&2; exit 2`}, HookInput{})
if err != nil {
t.Fatalf("exit 2 should not be an error, got %v", err)
}
if !out.blocks() || out.Reason != "denied" {
t.Fatalf("unexpected out: %+v", out)
}
})
t.Run("exit 1 is failure", func(t *testing.T) {
_, err := r.Run(ctx, HookConfig{Command: `echo boom >&2; exit 1`}, HookInput{})
if err == nil {
t.Fatal("expected error for exit 1")
}
})
t.Run("command not found is failure", func(t *testing.T) {
_, err := r.Run(ctx, HookConfig{Command: `this-command-does-not-exist-pigo`}, HookInput{})
if err == nil {
t.Fatal("expected error for missing command")
}
})
}
func TestRunnerTimeout(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("sh -c not available on windows")
}
r := &Runner{ProjectDir: t.TempDir()}
start := time.Now()
_, err := r.Run(context.Background(), HookConfig{Command: "sleep 5", Timeout: ptr(1)}, HookInput{})
if err == nil || !strings.Contains(err.Error(), "timed out") {
t.Fatalf("expected timeout error, got %v", err)
}
if time.Since(start) > 3*time.Second {
t.Fatalf("timeout took too long: %v", time.Since(start))
}
}
func TestRunnerOutputCap(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("sh -c not available on windows")
}
var buf cappedBuffer
buf.limit = 10
n, _ := buf.Write([]byte("0123456789abcdef"))
if n != 16 {
t.Fatalf("Write should report full length, got %d", n)
}
if len(buf.Bytes()) != 10 {
t.Fatalf("expected 10 bytes retained, got %d", len(buf.Bytes()))
}
if !buf.truncated() {
t.Fatal("expected truncated to be true")
}
}