Go 94 lines
package hooks
import (
"os"
"path/filepath"
"strings"
"testing"
"github.com/ajhahnde/eeco/internal/cockpit"
"github.com/ajhahnde/eeco/internal/config"
"github.com/ajhahnde/eeco/internal/playbooks"
)
// orientCfg builds a config with a workspace + private user dir for the
// SessionStart orient blocks (no git: LatestSemverTag degrades to "").
func orientCfg(t *testing.T) *config.Config {
t.Helper()
root := t.TempDir()
ws := filepath.Join(root, "tester", ".eeco")
if err := os.MkdirAll(filepath.Join(ws, "state"), 0o755); err != nil {
t.Fatal(err)
}
return &config.Config{
RepoRoot: root,
UserDir: filepath.Join(root, "tester"),
WorkspaceName: ".eeco",
Workspace: ws,
}
}
func TestLiveStateBlock_ShowsNewestNote(t *testing.T) {
cfg := orientCfg(t)
notesDir := filepath.Join(cfg.Workspace, "notes")
if err := os.MkdirAll(notesDir, 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(notesDir, "2026-06-05-150000-resume.md"), []byte("resume here next time"), 0o644); err != nil {
t.Fatal(err)
}
got := liveStateBlock(cfg)
if !strings.Contains(got, "newest handover") || !strings.Contains(got, "resume here next time") {
t.Errorf("liveStateBlock missing the handover note: %q", got)
}
}
func TestLiveStateBlock_EmptyWhenNothing(t *testing.T) {
if got := liveStateBlock(orientCfg(t)); got != "" {
t.Errorf("liveStateBlock should be empty with no tag/note, got %q", got)
}
}
func TestNewestHandover_GlobWins(t *testing.T) {
cfg := orientCfg(t)
if err := os.WriteFile(filepath.Join(cfg.RepoRoot, "HANDOVER.md"), []byte("x"), 0o644); err != nil {
t.Fatal(err)
}
cfg.HandoverGlob = "HANDOVER*.md"
if got := newestHandover(cfg); got != "HANDOVER.md" {
t.Errorf("newestHandover with glob = %q, want HANDOVER.md", got)
}
}
func TestDriftBlock_SilentThenFlagsDrift(t *testing.T) {
cfg := orientCfg(t)
// No cockpit generated → silent (empty-ledger gate).
if got := driftBlock(cfg); got != "" {
t.Errorf("driftBlock should be silent on an unused cockpit, got %q", got)
}
// Narrow the selection to handover so generating it alone leaves no
// "missing" findings for the other playbooks (the default selection is all).
if err := cockpit.SaveSelection(cfg, cockpit.Selection{Targets: []string{"claude"}, Playbooks: []string{"handover"}}); err != nil {
t.Fatal(err)
}
pb, err := playbooks.Get("handover")
if err != nil {
t.Fatal(err)
}
if _, err := cockpit.Generate(cfg, pb, "claude"); err != nil {
t.Fatal(err)
}
// Clean → still silent.
if got := driftBlock(cfg); got != "" {
t.Errorf("driftBlock should be silent when clean, got %q", got)
}
// Hand-edit → drift surfaces.
dst := filepath.Join(cfg.UserDir, ".claude", "skills", "handover", "SKILL.md")
if err := os.WriteFile(dst, []byte("edited\n"), 0o644); err != nil {
t.Fatal(err)
}
if got := driftBlock(cfg); !strings.Contains(got, "cockpit drift") {
t.Errorf("driftBlock should report drift after a hand-edit, got %q", got)
}
}