* test(doctor): add comprehensive tests for fix and check functions Add edge case tests, e2e tests, and improve test coverage for: - database_test.go: database integrity and sync checks - git_test.go: git hooks, merge driver, sync branch tests - gitignore_test.go: gitignore validation - prefix_test.go: ID prefix handling - fix/fix_test.go: fix operations - fix/e2e_test.go: end-to-end fix scenarios - fix/fix_edge_cases_test.go: edge case handling * docs: add testing philosophy and anti-patterns guide - Create TESTING_PHILOSOPHY.md covering test pyramid, priority matrix, what NOT to test, and 5 anti-patterns with code examples - Add cross-reference from README_TESTING.md - Document beads-specific guidance (well-covered areas vs gaps) - Include target metrics (test-to-code ratio, execution time targets) * chore: revert .beads/ to upstream/main state * refactor(doctor): add category grouping and Ayu theme colors - Add Category field to DoctorCheck for organizing checks by type - Define category constants: Core, Git, Runtime, Data, Integration, Metadata - Update thanks command to use shared Ayu color palette from internal/ui - Simplify test fixtures by removing redundant test cases * fix(doctor): prevent test fork bomb and fix test failures - Add ErrTestBinary guard in getBdBinary() to prevent tests from recursively executing the test binary when calling bd subcommands - Update claude_test.go to use new check names (CLI Availability, Prime Documentation) - Fix syncbranch test path comparison by resolving symlinks (/var vs /private/var on macOS) - Fix permissions check to use exact comparison instead of bitmask - Fix UntrackedJSONL to use git commit --only to preserve staged changes - Fix MergeDriver edge case test by making both .git dir and config read-only - Add skipIfTestBinary helper for E2E tests that need real bd binary * test(doctor): skip read-only config test in CI environments GitHub Actions containers may have CAP_DAC_OVERRIDE or similar capabilities that allow writing to read-only files, causing the test to fail. Skip the test when CI=true or GITHUB_ACTIONS=true.
118 lines
3.0 KiB
Go
118 lines
3.0 KiB
Go
package doctor
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
func TestCheckInstallation(t *testing.T) {
|
|
t.Run("missing beads directory", func(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
check := CheckInstallation(tmpDir)
|
|
|
|
if check.Status != StatusError {
|
|
t.Errorf("expected StatusError, got %s", check.Status)
|
|
}
|
|
if check.Name != "Installation" {
|
|
t.Errorf("expected name 'Installation', got %s", check.Name)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestCheckMultipleDatabases(t *testing.T) {
|
|
t.Run("no beads directory", func(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
check := CheckMultipleDatabases(tmpDir)
|
|
|
|
if check.Status != StatusOK {
|
|
t.Errorf("expected StatusOK for missing dir, got %s", check.Status)
|
|
}
|
|
})
|
|
|
|
t.Run("single database", func(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
beadsDir := filepath.Join(tmpDir, ".beads")
|
|
if err := os.Mkdir(beadsDir, 0755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// Create single db file
|
|
if err := os.WriteFile(filepath.Join(beadsDir, "beads.db"), []byte{}, 0644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
check := CheckMultipleDatabases(tmpDir)
|
|
|
|
if check.Status != StatusOK {
|
|
t.Errorf("expected StatusOK for single db, got %s", check.Status)
|
|
}
|
|
})
|
|
|
|
t.Run("multiple databases", func(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
beadsDir := filepath.Join(tmpDir, ".beads")
|
|
if err := os.Mkdir(beadsDir, 0755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// Create multiple db files
|
|
for _, name := range []string{"beads.db", "issues.db", "another.db"} {
|
|
if err := os.WriteFile(filepath.Join(beadsDir, name), []byte{}, 0644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
check := CheckMultipleDatabases(tmpDir)
|
|
|
|
if check.Status != StatusWarning {
|
|
t.Errorf("expected StatusWarning for multiple dbs, got %s", check.Status)
|
|
}
|
|
})
|
|
|
|
t.Run("backup files ignored", func(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
beadsDir := filepath.Join(tmpDir, ".beads")
|
|
if err := os.Mkdir(beadsDir, 0755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// Create one real db and one backup
|
|
if err := os.WriteFile(filepath.Join(beadsDir, "beads.db"), []byte{}, 0644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(beadsDir, "beads.backup.db"), []byte{}, 0644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
check := CheckMultipleDatabases(tmpDir)
|
|
|
|
if check.Status != StatusOK {
|
|
t.Errorf("expected StatusOK (backup ignored), got %s", check.Status)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestCheckPermissions(t *testing.T) {
|
|
t.Run("no beads directory", func(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
check := CheckPermissions(tmpDir)
|
|
|
|
// Should return error when .beads dir doesn't exist (can't write to it)
|
|
if check.Status != StatusError {
|
|
t.Errorf("expected StatusError for missing dir, got %s", check.Status)
|
|
}
|
|
})
|
|
|
|
t.Run("writable directory", func(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
beadsDir := filepath.Join(tmpDir, ".beads")
|
|
if err := os.Mkdir(beadsDir, 0755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
check := CheckPermissions(tmpDir)
|
|
|
|
if check.Status != StatusOK {
|
|
t.Errorf("expected StatusOK for writable dir, got %s", check.Status)
|
|
}
|
|
})
|
|
}
|