Same fix as crew: polecat manager was overwriting project CLAUDE.md with Gas Town polecat context. Gas Town context is now injected ephemerally via SessionStart hook (gt prime) only. Removed installCLAUDETemplate function and associated tests.
272 lines
6.5 KiB
Go
272 lines
6.5 KiB
Go
package polecat
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/steveyegge/gastown/internal/git"
|
|
"github.com/steveyegge/gastown/internal/rig"
|
|
)
|
|
|
|
func TestStateIsActive(t *testing.T) {
|
|
tests := []struct {
|
|
state State
|
|
active bool
|
|
}{
|
|
{StateWorking, true},
|
|
{StateDone, false},
|
|
{StateStuck, false},
|
|
// Legacy states are treated as active
|
|
{StateIdle, true},
|
|
{StateActive, true},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
if got := tt.state.IsActive(); got != tt.active {
|
|
t.Errorf("%s.IsActive() = %v, want %v", tt.state, got, tt.active)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestStateIsWorking(t *testing.T) {
|
|
tests := []struct {
|
|
state State
|
|
working bool
|
|
}{
|
|
{StateIdle, false},
|
|
{StateActive, false},
|
|
{StateWorking, true},
|
|
{StateDone, false},
|
|
{StateStuck, false},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
if got := tt.state.IsWorking(); got != tt.working {
|
|
t.Errorf("%s.IsWorking() = %v, want %v", tt.state, got, tt.working)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPolecatSummary(t *testing.T) {
|
|
p := &Polecat{
|
|
Name: "Toast",
|
|
State: StateWorking,
|
|
Issue: "gt-abc",
|
|
}
|
|
|
|
summary := p.Summary()
|
|
if summary.Name != "Toast" {
|
|
t.Errorf("Name = %q, want Toast", summary.Name)
|
|
}
|
|
if summary.State != StateWorking {
|
|
t.Errorf("State = %v, want StateWorking", summary.State)
|
|
}
|
|
if summary.Issue != "gt-abc" {
|
|
t.Errorf("Issue = %q, want gt-abc", summary.Issue)
|
|
}
|
|
}
|
|
|
|
func TestListEmpty(t *testing.T) {
|
|
root := t.TempDir()
|
|
r := &rig.Rig{
|
|
Name: "test-rig",
|
|
Path: root,
|
|
}
|
|
m := NewManager(r, git.NewGit(root))
|
|
|
|
polecats, err := m.List()
|
|
if err != nil {
|
|
t.Fatalf("List: %v", err)
|
|
}
|
|
if len(polecats) != 0 {
|
|
t.Errorf("polecats count = %d, want 0", len(polecats))
|
|
}
|
|
}
|
|
|
|
func TestGetNotFound(t *testing.T) {
|
|
root := t.TempDir()
|
|
r := &rig.Rig{
|
|
Name: "test-rig",
|
|
Path: root,
|
|
}
|
|
m := NewManager(r, git.NewGit(root))
|
|
|
|
_, err := m.Get("nonexistent")
|
|
if err != ErrPolecatNotFound {
|
|
t.Errorf("Get = %v, want ErrPolecatNotFound", err)
|
|
}
|
|
}
|
|
|
|
func TestRemoveNotFound(t *testing.T) {
|
|
root := t.TempDir()
|
|
r := &rig.Rig{
|
|
Name: "test-rig",
|
|
Path: root,
|
|
}
|
|
m := NewManager(r, git.NewGit(root))
|
|
|
|
err := m.Remove("nonexistent", false)
|
|
if err != ErrPolecatNotFound {
|
|
t.Errorf("Remove = %v, want ErrPolecatNotFound", err)
|
|
}
|
|
}
|
|
|
|
func TestPolecatDir(t *testing.T) {
|
|
r := &rig.Rig{
|
|
Name: "test-rig",
|
|
Path: "/home/user/ai/test-rig",
|
|
}
|
|
m := NewManager(r, git.NewGit(r.Path))
|
|
|
|
dir := m.polecatDir("Toast")
|
|
expected := "/home/user/ai/test-rig/polecats/Toast"
|
|
if dir != expected {
|
|
t.Errorf("polecatDir = %q, want %q", dir, expected)
|
|
}
|
|
}
|
|
|
|
func TestAssigneeID(t *testing.T) {
|
|
r := &rig.Rig{
|
|
Name: "test-rig",
|
|
Path: "/home/user/ai/test-rig",
|
|
}
|
|
m := NewManager(r, git.NewGit(r.Path))
|
|
|
|
id := m.assigneeID("Toast")
|
|
expected := "test-rig/Toast"
|
|
if id != expected {
|
|
t.Errorf("assigneeID = %q, want %q", id, expected)
|
|
}
|
|
}
|
|
|
|
// Note: State persistence tests removed - state is now derived from beads assignee field.
|
|
// Integration tests should verify beads-based state management.
|
|
|
|
func TestGetReturnsIdleWithoutBeads(t *testing.T) {
|
|
// When beads is not available, Get should return StateIdle
|
|
root := t.TempDir()
|
|
polecatDir := filepath.Join(root, "polecats", "Test")
|
|
if err := os.MkdirAll(polecatDir, 0755); err != nil {
|
|
t.Fatalf("mkdir: %v", err)
|
|
}
|
|
|
|
// Create mayor/rig directory for beads (but no actual beads)
|
|
mayorRigDir := filepath.Join(root, "mayor", "rig")
|
|
if err := os.MkdirAll(mayorRigDir, 0755); err != nil {
|
|
t.Fatalf("mkdir mayor/rig: %v", err)
|
|
}
|
|
|
|
r := &rig.Rig{
|
|
Name: "test-rig",
|
|
Path: root,
|
|
}
|
|
m := NewManager(r, git.NewGit(root))
|
|
|
|
// Get should return polecat with StateIdle (no beads = no assignment)
|
|
polecat, err := m.Get("Test")
|
|
if err != nil {
|
|
t.Fatalf("Get: %v", err)
|
|
}
|
|
|
|
if polecat.Name != "Test" {
|
|
t.Errorf("Name = %q, want Test", polecat.Name)
|
|
}
|
|
if polecat.State != StateIdle {
|
|
t.Errorf("State = %v, want StateIdle (beads not available)", polecat.State)
|
|
}
|
|
}
|
|
|
|
func TestListWithPolecats(t *testing.T) {
|
|
root := t.TempDir()
|
|
|
|
// Create some polecat directories (state is now derived from beads, not state files)
|
|
for _, name := range []string{"Toast", "Cheedo"} {
|
|
polecatDir := filepath.Join(root, "polecats", name)
|
|
if err := os.MkdirAll(polecatDir, 0755); err != nil {
|
|
t.Fatalf("mkdir: %v", err)
|
|
}
|
|
}
|
|
// Create mayor/rig for beads path
|
|
mayorRig := filepath.Join(root, "mayor", "rig")
|
|
if err := os.MkdirAll(mayorRig, 0755); err != nil {
|
|
t.Fatalf("mkdir mayor/rig: %v", err)
|
|
}
|
|
|
|
r := &rig.Rig{
|
|
Name: "test-rig",
|
|
Path: root,
|
|
}
|
|
m := NewManager(r, git.NewGit(root))
|
|
|
|
polecats, err := m.List()
|
|
if err != nil {
|
|
t.Fatalf("List: %v", err)
|
|
}
|
|
if len(polecats) != 2 {
|
|
t.Errorf("polecats count = %d, want 2", len(polecats))
|
|
}
|
|
}
|
|
|
|
// Note: TestSetState, TestAssignIssue, and TestClearIssue were removed.
|
|
// These operations now require a running beads instance and are tested
|
|
// via integration tests. The unit tests here focus on testing the basic
|
|
// polecat lifecycle operations that don't require beads.
|
|
|
|
func TestSetStateWithoutBeads(t *testing.T) {
|
|
// SetState should not error when beads is not available
|
|
root := t.TempDir()
|
|
polecatDir := filepath.Join(root, "polecats", "Test")
|
|
if err := os.MkdirAll(polecatDir, 0755); err != nil {
|
|
t.Fatalf("mkdir: %v", err)
|
|
}
|
|
// Create mayor/rig for beads path
|
|
mayorRig := filepath.Join(root, "mayor", "rig")
|
|
if err := os.MkdirAll(mayorRig, 0755); err != nil {
|
|
t.Fatalf("mkdir mayor/rig: %v", err)
|
|
}
|
|
|
|
r := &rig.Rig{
|
|
Name: "test-rig",
|
|
Path: root,
|
|
}
|
|
m := NewManager(r, git.NewGit(root))
|
|
|
|
// SetState should succeed (no-op when no issue assigned)
|
|
err := m.SetState("Test", StateActive)
|
|
if err != nil {
|
|
t.Errorf("SetState: %v (expected no error when no beads/issue)", err)
|
|
}
|
|
}
|
|
|
|
func TestClearIssueWithoutAssignment(t *testing.T) {
|
|
// ClearIssue should not error when no issue is assigned
|
|
root := t.TempDir()
|
|
polecatDir := filepath.Join(root, "polecats", "Test")
|
|
if err := os.MkdirAll(polecatDir, 0755); err != nil {
|
|
t.Fatalf("mkdir: %v", err)
|
|
}
|
|
// Create mayor/rig for beads path
|
|
mayorRig := filepath.Join(root, "mayor", "rig")
|
|
if err := os.MkdirAll(mayorRig, 0755); err != nil {
|
|
t.Fatalf("mkdir mayor/rig: %v", err)
|
|
}
|
|
|
|
r := &rig.Rig{
|
|
Name: "test-rig",
|
|
Path: root,
|
|
}
|
|
m := NewManager(r, git.NewGit(root))
|
|
|
|
// ClearIssue should succeed even when no issue assigned
|
|
err := m.ClearIssue("Test")
|
|
if err != nil {
|
|
t.Errorf("ClearIssue: %v (expected no error when no assignment)", err)
|
|
}
|
|
}
|
|
|
|
// NOTE: TestInstallCLAUDETemplate tests were removed.
|
|
// We no longer write CLAUDE.md to worktrees - Gas Town context is injected
|
|
// ephemerally via SessionStart hook (gt prime) to prevent leaking internal
|
|
// architecture into project repos.
|