Use flush-only workflow when no git remote is configured Detects local-only repos (no git remote) and provides appropriate instructions: - bd sync --flush-only instead of full git workflow - Clear note about local-only storage - Prevents confusing git errors for non-git users
203 lines
6.2 KiB
Go
203 lines
6.2 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestOutputContextFunction(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
mcpMode bool
|
|
stealthMode bool
|
|
ephemeralMode bool
|
|
localOnlyMode bool
|
|
expectText []string
|
|
rejectText []string
|
|
}{
|
|
{
|
|
name: "CLI Normal (non-ephemeral)",
|
|
mcpMode: false,
|
|
stealthMode: false,
|
|
ephemeralMode: false,
|
|
localOnlyMode: false,
|
|
expectText: []string{"Beads Workflow Context", "bd sync", "git push"},
|
|
rejectText: []string{"bd sync --flush-only", "--from-main"},
|
|
},
|
|
{
|
|
name: "CLI Normal (ephemeral)",
|
|
mcpMode: false,
|
|
stealthMode: false,
|
|
ephemeralMode: true,
|
|
localOnlyMode: false,
|
|
expectText: []string{"Beads Workflow Context", "bd sync --from-main", "ephemeral branch"},
|
|
rejectText: []string{"bd sync --flush-only", "git push"},
|
|
},
|
|
{
|
|
name: "CLI Stealth",
|
|
mcpMode: false,
|
|
stealthMode: true,
|
|
ephemeralMode: false, // stealth mode overrides ephemeral detection
|
|
localOnlyMode: false,
|
|
expectText: []string{"Beads Workflow Context", "bd sync --flush-only"},
|
|
rejectText: []string{"git push", "git pull", "git commit", "git status", "git add"},
|
|
},
|
|
{
|
|
name: "CLI Local-only (no git remote)",
|
|
mcpMode: false,
|
|
stealthMode: false,
|
|
ephemeralMode: false,
|
|
localOnlyMode: true,
|
|
expectText: []string{"Beads Workflow Context", "bd sync --flush-only", "No git remote configured"},
|
|
rejectText: []string{"git push", "git pull", "--from-main"},
|
|
},
|
|
{
|
|
name: "CLI Local-only overrides ephemeral",
|
|
mcpMode: false,
|
|
stealthMode: false,
|
|
ephemeralMode: true, // ephemeral is true but local-only takes precedence
|
|
localOnlyMode: true,
|
|
expectText: []string{"Beads Workflow Context", "bd sync --flush-only", "No git remote configured"},
|
|
rejectText: []string{"git push", "--from-main", "ephemeral branch"},
|
|
},
|
|
{
|
|
name: "CLI Stealth overrides local-only",
|
|
mcpMode: false,
|
|
stealthMode: true,
|
|
ephemeralMode: false,
|
|
localOnlyMode: true, // local-only is true but stealth takes precedence
|
|
expectText: []string{"Beads Workflow Context", "bd sync --flush-only"},
|
|
rejectText: []string{"git push", "git pull", "git commit", "git status", "git add", "No git remote configured"},
|
|
},
|
|
{
|
|
name: "MCP Normal (non-ephemeral)",
|
|
mcpMode: true,
|
|
stealthMode: false,
|
|
ephemeralMode: false,
|
|
localOnlyMode: false,
|
|
expectText: []string{"Beads Issue Tracker Active", "bd sync", "git push"},
|
|
rejectText: []string{"bd sync --flush-only", "--from-main"},
|
|
},
|
|
{
|
|
name: "MCP Normal (ephemeral)",
|
|
mcpMode: true,
|
|
stealthMode: false,
|
|
ephemeralMode: true,
|
|
localOnlyMode: false,
|
|
expectText: []string{"Beads Issue Tracker Active", "bd sync --from-main", "ephemeral branch"},
|
|
rejectText: []string{"bd sync --flush-only", "git push"},
|
|
},
|
|
{
|
|
name: "MCP Stealth",
|
|
mcpMode: true,
|
|
stealthMode: true,
|
|
ephemeralMode: false, // stealth mode overrides ephemeral detection
|
|
localOnlyMode: false,
|
|
expectText: []string{"Beads Issue Tracker Active", "bd sync --flush-only"},
|
|
rejectText: []string{"git push", "git pull", "git commit", "git status", "git add"},
|
|
},
|
|
{
|
|
name: "MCP Local-only (no git remote)",
|
|
mcpMode: true,
|
|
stealthMode: false,
|
|
ephemeralMode: false,
|
|
localOnlyMode: true,
|
|
expectText: []string{"Beads Issue Tracker Active", "bd sync --flush-only"},
|
|
rejectText: []string{"git push", "git pull", "--from-main"},
|
|
},
|
|
{
|
|
name: "MCP Local-only overrides ephemeral",
|
|
mcpMode: true,
|
|
stealthMode: false,
|
|
ephemeralMode: true, // ephemeral is true but local-only takes precedence
|
|
localOnlyMode: true,
|
|
expectText: []string{"Beads Issue Tracker Active", "bd sync --flush-only"},
|
|
rejectText: []string{"git push", "--from-main", "ephemeral branch"},
|
|
},
|
|
{
|
|
name: "MCP Stealth overrides local-only",
|
|
mcpMode: true,
|
|
stealthMode: true,
|
|
ephemeralMode: false,
|
|
localOnlyMode: true, // local-only is true but stealth takes precedence
|
|
expectText: []string{"Beads Issue Tracker Active", "bd sync --flush-only"},
|
|
rejectText: []string{"git push", "git pull", "git commit", "git status", "git add"},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
defer stubIsEphemeralBranch(tt.ephemeralMode)()
|
|
defer stubIsDaemonAutoSyncing(false)() // Default: no auto-sync in tests
|
|
defer stubPrimeHasGitRemote(!tt.localOnlyMode)() // localOnly = !primeHasGitRemote
|
|
|
|
var buf bytes.Buffer
|
|
err := outputPrimeContext(&buf, tt.mcpMode, tt.stealthMode)
|
|
if err != nil {
|
|
t.Fatalf("outputPrimeContext failed: %v", err)
|
|
}
|
|
|
|
output := buf.String()
|
|
|
|
for _, expected := range tt.expectText {
|
|
if !strings.Contains(output, expected) {
|
|
t.Errorf("Expected text not found: %s", expected)
|
|
}
|
|
}
|
|
|
|
for _, rejected := range tt.rejectText {
|
|
if strings.Contains(output, rejected) {
|
|
t.Errorf("Unexpected text found: %s", rejected)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// stubIsEphemeralBranch temporarily replaces isEphemeralBranch
|
|
// with a stub returning returnValue.
|
|
//
|
|
// Returns a function to restore the original isEphemeralBranch.
|
|
// Usage:
|
|
//
|
|
// defer stubIsEphemeralBranch(true)()
|
|
func stubIsEphemeralBranch(isEphem bool) func() {
|
|
original := isEphemeralBranch
|
|
isEphemeralBranch = func() bool {
|
|
return isEphem
|
|
}
|
|
return func() {
|
|
isEphemeralBranch = original
|
|
}
|
|
}
|
|
|
|
// stubIsDaemonAutoSyncing temporarily replaces isDaemonAutoSyncing
|
|
// with a stub returning returnValue.
|
|
func stubIsDaemonAutoSyncing(isAutoSync bool) func() {
|
|
original := isDaemonAutoSyncing
|
|
isDaemonAutoSyncing = func() bool {
|
|
return isAutoSync
|
|
}
|
|
return func() {
|
|
isDaemonAutoSyncing = original
|
|
}
|
|
}
|
|
|
|
// stubPrimeHasGitRemote temporarily replaces primeHasGitRemote
|
|
// with a stub returning returnValue.
|
|
//
|
|
// Returns a function to restore the original primeHasGitRemote.
|
|
// Usage:
|
|
//
|
|
// defer stubPrimeHasGitRemote(true)()
|
|
func stubPrimeHasGitRemote(hasRemote bool) func() {
|
|
original := primeHasGitRemote
|
|
primeHasGitRemote = func() bool {
|
|
return hasRemote
|
|
}
|
|
return func() {
|
|
primeHasGitRemote = original
|
|
}
|
|
}
|