Analysis found these commands are dead code: - gt never calls `bd pin` - uses `bd update --status=pinned` instead - Beads.Pin() wrapper exists but is never called - bd hook functionality duplicated by gt mol status - Code comment says "pinned field is cosmetic for bd hook visibility" Removed: - cmd/bd/pin.go - cmd/bd/unpin.go - cmd/bd/hook.go 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
145 lines
3.3 KiB
Go
145 lines
3.3 KiB
Go
package routing
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
func TestDetermineTargetRepo(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
config *RoutingConfig
|
|
userRole UserRole
|
|
repoPath string
|
|
want string
|
|
}{
|
|
{
|
|
name: "explicit override takes precedence",
|
|
config: &RoutingConfig{
|
|
Mode: "auto",
|
|
DefaultRepo: "~/planning",
|
|
MaintainerRepo: ".",
|
|
ContributorRepo: "~/contributor-planning",
|
|
ExplicitOverride: "/tmp/custom",
|
|
},
|
|
userRole: Maintainer,
|
|
repoPath: ".",
|
|
want: "/tmp/custom",
|
|
},
|
|
{
|
|
name: "auto mode - maintainer uses maintainer repo",
|
|
config: &RoutingConfig{
|
|
Mode: "auto",
|
|
MaintainerRepo: ".",
|
|
ContributorRepo: "~/contributor-planning",
|
|
},
|
|
userRole: Maintainer,
|
|
repoPath: ".",
|
|
want: ".",
|
|
},
|
|
{
|
|
name: "auto mode - contributor uses contributor repo",
|
|
config: &RoutingConfig{
|
|
Mode: "auto",
|
|
MaintainerRepo: ".",
|
|
ContributorRepo: "~/contributor-planning",
|
|
},
|
|
userRole: Contributor,
|
|
repoPath: ".",
|
|
want: "~/contributor-planning",
|
|
},
|
|
{
|
|
name: "explicit mode uses default",
|
|
config: &RoutingConfig{
|
|
Mode: "explicit",
|
|
DefaultRepo: "~/planning",
|
|
},
|
|
userRole: Maintainer,
|
|
repoPath: ".",
|
|
want: "~/planning",
|
|
},
|
|
{
|
|
name: "no config defaults to current directory",
|
|
config: &RoutingConfig{
|
|
Mode: "auto",
|
|
},
|
|
userRole: Maintainer,
|
|
repoPath: ".",
|
|
want: ".",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := DetermineTargetRepo(tt.config, tt.userRole, tt.repoPath)
|
|
if got != tt.want {
|
|
t.Errorf("DetermineTargetRepo() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDetectUserRole_Fallback(t *testing.T) {
|
|
// Test fallback behavior when git is not available
|
|
role, err := DetectUserRole("/nonexistent/path/that/does/not/exist")
|
|
if err != nil {
|
|
t.Fatalf("DetectUserRole() error = %v, want nil", err)
|
|
}
|
|
if role != Contributor {
|
|
t.Errorf("DetectUserRole() = %v, want %v (fallback)", role, Contributor)
|
|
}
|
|
}
|
|
|
|
func TestExtractPrefix(t *testing.T) {
|
|
tests := []struct {
|
|
id string
|
|
want string
|
|
}{
|
|
{"gt-abc123", "gt-"},
|
|
{"bd-xyz", "bd-"},
|
|
{"hq-1234", "hq-"},
|
|
{"abc123", ""}, // No hyphen
|
|
{"", ""}, // Empty string
|
|
{"-abc", "-"}, // Starts with hyphen
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.id, func(t *testing.T) {
|
|
got := ExtractPrefix(tt.id)
|
|
if got != tt.want {
|
|
t.Errorf("ExtractPrefix(%q) = %q, want %q", tt.id, got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestExtractProjectFromPath(t *testing.T) {
|
|
tests := []struct {
|
|
path string
|
|
want string
|
|
}{
|
|
{"beads/mayor/rig", "beads"},
|
|
{"gastown/crew/max", "gastown"},
|
|
{"simple", "simple"},
|
|
{"", ""},
|
|
{"/absolute/path", ""}, // Starts with /, first component is empty
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.path, func(t *testing.T) {
|
|
got := ExtractProjectFromPath(tt.path)
|
|
if got != tt.want {
|
|
t.Errorf("ExtractProjectFromPath(%q) = %q, want %q", tt.path, got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestResolveToExternalRef(t *testing.T) {
|
|
// This test is limited since it requires a routes.jsonl file
|
|
// Just test that it returns empty string for nonexistent directory
|
|
got := ResolveToExternalRef("bd-abc", "/nonexistent/path")
|
|
if got != "" {
|
|
t.Errorf("ResolveToExternalRef() = %q, want empty string for nonexistent path", got)
|
|
}
|
|
}
|