test: add coverage for GH#807 sync.branch main/master rejection
- Add TestSet cases for main/master rejection in syncbranch_test.go - Add TestInitWithSyncBranch to verify --branch flag works - Add TestInitWithoutBranchFlag to verify no auto-detection (root cause) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -183,6 +183,96 @@ func TestInitCommand(t *testing.T) {
|
|||||||
|
|
||||||
// Note: Error case testing is omitted because the init command calls os.Exit()
|
// Note: Error case testing is omitted because the init command calls os.Exit()
|
||||||
// on errors, which makes it difficult to test in a unit test context.
|
// on errors, which makes it difficult to test in a unit test context.
|
||||||
|
// GH#807: Rejection of main/master as sync branch is tested at unit level in
|
||||||
|
// internal/syncbranch/syncbranch_test.go (TestValidateSyncBranchName, TestSet).
|
||||||
|
|
||||||
|
// TestInitWithSyncBranch verifies that --branch flag correctly sets sync.branch
|
||||||
|
// GH#807: Also verifies that valid sync branches work (rejection is tested at unit level)
|
||||||
|
func TestInitWithSyncBranch(t *testing.T) {
|
||||||
|
// Reset global state
|
||||||
|
origDBPath := dbPath
|
||||||
|
defer func() { dbPath = origDBPath }()
|
||||||
|
dbPath = ""
|
||||||
|
|
||||||
|
// Reset Cobra flags
|
||||||
|
initCmd.Flags().Set("branch", "")
|
||||||
|
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
t.Chdir(tmpDir)
|
||||||
|
|
||||||
|
// Initialize git repo first (needed for sync branch to make sense)
|
||||||
|
if err := runCommandInDir(tmpDir, "git", "init", "--initial-branch=dev"); err != nil {
|
||||||
|
t.Fatalf("Failed to init git: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run bd init with --branch flag
|
||||||
|
rootCmd.SetArgs([]string{"init", "--prefix", "test", "--branch", "beads-sync", "--quiet"})
|
||||||
|
if err := rootCmd.Execute(); err != nil {
|
||||||
|
t.Fatalf("Init with --branch failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify database was created
|
||||||
|
dbFilePath := filepath.Join(tmpDir, ".beads", "beads.db")
|
||||||
|
store, err := openExistingTestDB(t, dbFilePath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to open database: %v", err)
|
||||||
|
}
|
||||||
|
defer store.Close()
|
||||||
|
|
||||||
|
// Verify sync.branch was set correctly
|
||||||
|
ctx := context.Background()
|
||||||
|
syncBranch, err := store.GetConfig(ctx, "sync.branch")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to get sync.branch from database: %v", err)
|
||||||
|
}
|
||||||
|
if syncBranch != "beads-sync" {
|
||||||
|
t.Errorf("Expected sync.branch 'beads-sync', got %q", syncBranch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestInitWithoutBranchFlag verifies that sync.branch is NOT auto-set when --branch is omitted
|
||||||
|
// GH#807: This was the root cause - init was auto-detecting current branch (e.g., main)
|
||||||
|
func TestInitWithoutBranchFlag(t *testing.T) {
|
||||||
|
// Reset global state
|
||||||
|
origDBPath := dbPath
|
||||||
|
defer func() { dbPath = origDBPath }()
|
||||||
|
dbPath = ""
|
||||||
|
|
||||||
|
// Reset Cobra flags
|
||||||
|
initCmd.Flags().Set("branch", "")
|
||||||
|
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
t.Chdir(tmpDir)
|
||||||
|
|
||||||
|
// Initialize git repo on 'main' branch
|
||||||
|
if err := runCommandInDir(tmpDir, "git", "init", "--initial-branch=main"); err != nil {
|
||||||
|
t.Fatalf("Failed to init git: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run bd init WITHOUT --branch flag
|
||||||
|
rootCmd.SetArgs([]string{"init", "--prefix", "test", "--quiet"})
|
||||||
|
if err := rootCmd.Execute(); err != nil {
|
||||||
|
t.Fatalf("Init failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify database was created
|
||||||
|
dbFilePath := filepath.Join(tmpDir, ".beads", "beads.db")
|
||||||
|
store, err := openExistingTestDB(t, dbFilePath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to open database: %v", err)
|
||||||
|
}
|
||||||
|
defer store.Close()
|
||||||
|
|
||||||
|
// Verify sync.branch was NOT set (empty = use current branch directly)
|
||||||
|
ctx := context.Background()
|
||||||
|
syncBranch, err := store.GetConfig(ctx, "sync.branch")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to get sync.branch from database: %v", err)
|
||||||
|
}
|
||||||
|
if syncBranch != "" {
|
||||||
|
t.Errorf("Expected sync.branch to be empty (not auto-detected), got %q", syncBranch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestInitAlreadyInitialized(t *testing.T) {
|
func TestInitAlreadyInitialized(t *testing.T) {
|
||||||
// Reset global state
|
// Reset global state
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package syncbranch
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/steveyegge/beads/internal/storage/sqlite"
|
"github.com/steveyegge/beads/internal/storage/sqlite"
|
||||||
@@ -222,6 +223,33 @@ func TestSet(t *testing.T) {
|
|||||||
t.Error("Set() expected error for invalid branch name, got nil")
|
t.Error("Set() expected error for invalid branch name, got nil")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// GH#807: Verify Set() rejects main/master (not just ValidateSyncBranchName)
|
||||||
|
t.Run("rejects main as sync branch", func(t *testing.T) {
|
||||||
|
store := newTestStore(t)
|
||||||
|
defer store.Close()
|
||||||
|
|
||||||
|
err := Set(ctx, store, "main")
|
||||||
|
if err == nil {
|
||||||
|
t.Error("Set() expected error for 'main', got nil")
|
||||||
|
}
|
||||||
|
if err != nil && !strings.Contains(err.Error(), "cannot use 'main'") {
|
||||||
|
t.Errorf("Set() error should mention 'cannot use main', got: %v", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("rejects master as sync branch", func(t *testing.T) {
|
||||||
|
store := newTestStore(t)
|
||||||
|
defer store.Close()
|
||||||
|
|
||||||
|
err := Set(ctx, store, "master")
|
||||||
|
if err == nil {
|
||||||
|
t.Error("Set() expected error for 'master', got nil")
|
||||||
|
}
|
||||||
|
if err != nil && !strings.Contains(err.Error(), "cannot use 'master'") {
|
||||||
|
t.Errorf("Set() error should mention 'cannot use master', got: %v", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnset(t *testing.T) {
|
func TestUnset(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user