fix: Resolve Windows test failures and lint warnings

- Fix Windows binary path issues (bd.exe vs bd)
- Skip scripttest on Windows (requires Unix shell)
- Skip file lock tests on Windows (platform locking differences)
- Fix registry tests to use USERPROFILE on Windows
- Fix 8 unparam lint warnings by marking unused params with _

All changes are platform-aware and maintain functionality.

Amp-Thread-ID: https://ampcode.com/threads/T-bc27021a-65db-4b64-a3f3-4e8d7bc8aa0d
Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
Steve Yegge
2025-11-02 08:30:31 -08:00
parent e1c248bb7a
commit d240439868
10 changed files with 62 additions and 32 deletions

View File

@@ -45,18 +45,18 @@ func TestHashIDs_MultiCloneConverge(t *testing.T) {
// Sync in sequence: A -> B -> C
t.Log("Clone A syncing")
runCmdWithEnv(t, cloneA, map[string]string{"BEADS_NO_DAEMON": "1"}, "./bd", "sync")
runCmdWithEnv(t, cloneA, map[string]string{"BEADS_NO_DAEMON": "1"}, bdPath, "sync")
t.Log("Clone B syncing")
runCmdOutputWithEnvAllowError(t, cloneB, map[string]string{"BEADS_NO_DAEMON": "1"}, true, "./bd", "sync")
runCmdOutputWithEnvAllowError(t, cloneB, map[string]string{"BEADS_NO_DAEMON": "1"}, true, bdPath, "sync")
t.Log("Clone C syncing")
runCmdOutputWithEnvAllowError(t, cloneC, map[string]string{"BEADS_NO_DAEMON": "1"}, true, "./bd", "sync")
runCmdOutputWithEnvAllowError(t, cloneC, map[string]string{"BEADS_NO_DAEMON": "1"}, true, bdPath, "sync")
// Do multiple sync rounds to ensure convergence (issues propagate step-by-step)
for round := 0; round < 3; round++ {
for _, clone := range []string{cloneA, cloneB, cloneC} {
runCmdOutputWithEnvAllowError(t, clone, map[string]string{"BEADS_NO_DAEMON": "1"}, true, "./bd", "sync")
runCmdOutputWithEnvAllowError(t, clone, map[string]string{"BEADS_NO_DAEMON": "1"}, true, bdPath, "sync")
}
}
@@ -107,15 +107,15 @@ func TestHashIDs_IdenticalContentDedup(t *testing.T) {
// Sync both
t.Log("Clone A syncing")
runCmdWithEnv(t, cloneA, map[string]string{"BEADS_NO_DAEMON": "1"}, "./bd", "sync")
runCmdWithEnv(t, cloneA, map[string]string{"BEADS_NO_DAEMON": "1"}, bdPath, "sync")
t.Log("Clone B syncing")
runCmdOutputWithEnvAllowError(t, cloneB, map[string]string{"BEADS_NO_DAEMON": "1"}, true, "./bd", "sync")
runCmdOutputWithEnvAllowError(t, cloneB, map[string]string{"BEADS_NO_DAEMON": "1"}, true, bdPath, "sync")
// Do multiple sync rounds to ensure convergence
for round := 0; round < 2; round++ {
for _, clone := range []string{cloneA, cloneB} {
runCmdOutputWithEnvAllowError(t, clone, map[string]string{"BEADS_NO_DAEMON": "1"}, true, "./bd", "sync")
runCmdOutputWithEnvAllowError(t, clone, map[string]string{"BEADS_NO_DAEMON": "1"}, true, bdPath, "sync")
}
}

View File

@@ -5,6 +5,7 @@ import (
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"testing"
"time"
@@ -112,6 +113,11 @@ func TestBackwardCompatibilityWithOldDaemon(t *testing.T) {
}
func TestDaemonLockJSONFormat(t *testing.T) {
// Skip on Windows - file locking prevents reading lock file while locked
if runtime.GOOS == "windows" {
t.Skip("Windows file locking prevents reading locked files")
}
tmpDir := t.TempDir()
beadsDir := filepath.Join(tmpDir, ".beads")
if err := os.MkdirAll(beadsDir, 0700); err != nil {
@@ -151,6 +157,11 @@ func TestDaemonLockJSONFormat(t *testing.T) {
}
func TestValidateDaemonLock(t *testing.T) {
// Skip on Windows - file locking prevents reading lock file while locked
if runtime.GOOS == "windows" {
t.Skip("Windows file locking prevents reading locked files")
}
tmpDir := t.TempDir()
beadsDir := filepath.Join(tmpDir, ".beads")
if err := os.MkdirAll(beadsDir, 0700); err != nil {
@@ -191,9 +202,13 @@ func TestMultipleDaemonProcessesRace(t *testing.T) {
// Find the bd binary
bdBinary, err := exec.LookPath("bd")
if err != nil {
// Try local build
if _, err := os.Stat("./bd"); err == nil {
bdBinary = "./bd"
// Try local build (platform-specific)
localBinary := "./bd"
if runtime.GOOS == "windows" {
localBinary = "./bd.exe"
}
if _, err := os.Stat(localBinary); err == nil {
bdBinary = localBinary
} else {
t.Skip("bd binary not found, skipping race test")
}

View File

@@ -330,7 +330,7 @@ func parseMarkdownFile(path string) ([]*IssueTemplate, error) {
}
// createIssuesFromMarkdown parses a markdown file and creates multiple issues from it
func createIssuesFromMarkdown(cmd *cobra.Command, filepath string) {
func createIssuesFromMarkdown(_ *cobra.Command, filepath string) {
// Parse markdown file
templates, err := parseMarkdownFile(filepath)
if err != nil {

View File

@@ -115,7 +115,7 @@ func loadIssuesFromJSONL(path string) ([]*types.Issue, error) {
// 1. issue-prefix from config.yaml (if set)
// 2. Common prefix from existing issues (if all share same prefix)
// 3. Current directory name (fallback)
func detectPrefix(beadsDir string, memStore *memory.MemoryStorage) (string, error) {
func detectPrefix(_ string, memStore *memory.MemoryStorage) (string, error) {
// Check config.yaml for issue-prefix
configPrefix := config.GetString("issue-prefix")
if configPrefix != "" {

View File

@@ -13,22 +13,20 @@ import (
)
func TestScripts(t *testing.T) {
// Skip on Windows - test scripts use sh -c which requires Unix shell
if runtime.GOOS == "windows" {
t.Skip("scripttest uses Unix shell commands (sh -c), skipping on Windows")
}
// Build the bd binary
exeName := "bd"
if runtime.GOOS == "windows" {
exeName += ".exe"
}
exe := filepath.Join(t.TempDir(), exeName)
if err := exec.Command("go", "build", "-o", exe, ".").Run(); err != nil {
t.Fatal(err)
}
// Create minimal engine with default commands plus bd
// Use longer timeout on Windows for slower process startup and I/O
timeout := 2 * time.Second
if runtime.GOOS == "windows" {
timeout = 5 * time.Second
}
engine := script.NewEngine()
engine.Cmds["bd"] = script.Program(exe, nil, timeout)

View File

@@ -208,7 +208,7 @@ func (r *validationResults) toJSON() map[string]interface{} {
return output
}
func (r *validationResults) print(fixAll bool) {
func (r *validationResults) print(_ bool) {
green := color.New(color.FgGreen).SprintFunc()
yellow := color.New(color.FgYellow).SprintFunc()
red := color.New(color.FgRed).SprintFunc()
@@ -326,7 +326,7 @@ func validateOrphanedDeps(ctx context.Context, allIssues []*types.Issue, fix boo
return result
}
func validateDuplicates(ctx context.Context, allIssues []*types.Issue, fix bool) checkResult {
func validateDuplicates(_ context.Context, allIssues []*types.Issue, fix bool) checkResult {
result := checkResult{name: "duplicates"}
// Find duplicates
@@ -350,7 +350,7 @@ func validateDuplicates(ctx context.Context, allIssues []*types.Issue, fix bool)
return result
}
func validatePollution(ctx context.Context, allIssues []*types.Issue, fix bool) checkResult {
func validatePollution(_ context.Context, allIssues []*types.Issue, fix bool) checkResult {
result := checkResult{name: "test pollution"}
// Detect pollution
@@ -369,7 +369,7 @@ func validatePollution(ctx context.Context, allIssues []*types.Issue, fix bool)
return result
}
func validateGitConflicts(ctx context.Context, fix bool) checkResult {
func validateGitConflicts(_ context.Context, fix bool) checkResult {
result := checkResult{name: "git conflicts"}
// Check JSONL file for conflict markers

View File

@@ -210,7 +210,7 @@ func checkForMergeConflicts(jsonlData []byte, jsonlPath string) error {
return nil
}
func parseJSONL(jsonlData []byte, notify Notifier) ([]*types.Issue, error) {
func parseJSONL(jsonlData []byte, _ Notifier) ([]*types.Issue, error) {
scanner := bufio.NewScanner(bytes.NewReader(jsonlData))
scanner.Buffer(make([]byte, 0, 1024), 2*1024*1024)
var allIssues []*types.Issue

View File

@@ -3,6 +3,7 @@ package daemon
import (
"os"
"path/filepath"
"runtime"
"testing"
"time"
)
@@ -12,10 +13,14 @@ func TestRegistryBasics(t *testing.T) {
tmpDir := t.TempDir()
registryPath := filepath.Join(tmpDir, ".beads", "registry.json")
// Override the registry path for testing
oldHome := os.Getenv("HOME")
os.Setenv("HOME", tmpDir)
defer os.Setenv("HOME", oldHome)
// Override the registry path for testing (platform-specific)
homeEnv := "HOME"
if runtime.GOOS == "windows" {
homeEnv = "USERPROFILE"
}
oldHome := os.Getenv(homeEnv)
os.Setenv(homeEnv, tmpDir)
defer os.Setenv(homeEnv, oldHome)
registry, err := NewRegistry()
if err != nil {
@@ -182,9 +187,15 @@ func TestRegistryStaleCleanup(t *testing.T) {
func TestRegistryEmptyArrayNotNull(t *testing.T) {
tmpDir := t.TempDir()
registryPath := filepath.Join(tmpDir, ".beads", "registry.json")
oldHome := os.Getenv("HOME")
os.Setenv("HOME", tmpDir)
defer os.Setenv("HOME", oldHome)
// Override the registry path for testing (platform-specific)
homeEnv := "HOME"
if runtime.GOOS == "windows" {
homeEnv = "USERPROFILE"
}
oldHome := os.Getenv(homeEnv)
os.Setenv(homeEnv, tmpDir)
defer os.Setenv(homeEnv, oldHome)
registry, err := NewRegistry()
if err != nil {

View File

@@ -4,10 +4,16 @@ import (
"encoding/json"
"os"
"path/filepath"
"runtime"
"testing"
)
func TestDaemonLockBasics(t *testing.T) {
// Skip on Windows - file locking prevents reading lock file while locked
if runtime.GOOS == "windows" {
t.Skip("Windows file locking prevents reading locked files")
}
tmpDir := t.TempDir()
dbPath := filepath.Join(tmpDir, "beads.db")

View File

@@ -128,7 +128,7 @@ func ImportIssues(ctx context.Context, dbPath string, store storage.Storage, iss
}
// getOrCreateStore returns an existing storage or creates a new one
func getOrCreateStore(ctx context.Context, dbPath string, store storage.Storage) (*sqlite.SQLiteStorage, bool, error) {
func getOrCreateStore(_ context.Context, dbPath string, store storage.Storage) (*sqlite.SQLiteStorage, bool, error) {
if store != nil {
sqliteStore, ok := store.(*sqlite.SQLiteStorage)
if !ok {