* 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.
87 lines
2.3 KiB
Go
87 lines
2.3 KiB
Go
package doctor
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
// TestIntegrityChecks_NoBeadsDir verifies all integrity check functions handle
|
|
// missing .beads directories gracefully. This replaces 4 individual subtests.
|
|
func TestIntegrityChecks_NoBeadsDir(t *testing.T) {
|
|
checks := []struct {
|
|
name string
|
|
fn func(string) DoctorCheck
|
|
wantName string
|
|
}{
|
|
{"IDFormat", CheckIDFormat, "Issue IDs"},
|
|
{"DependencyCycles", CheckDependencyCycles, "Dependency Cycles"},
|
|
{"Tombstones", CheckTombstones, "Tombstones"},
|
|
{"DeletionsManifest", CheckDeletionsManifest, "Deletions Manifest"},
|
|
}
|
|
|
|
for _, tc := range checks {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
result := tc.fn(tmpDir)
|
|
|
|
if result.Name != tc.wantName {
|
|
t.Errorf("Name = %q, want %q", result.Name, tc.wantName)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestIntegrityChecks_EmptyBeadsDir verifies all integrity check functions return OK
|
|
// when .beads directory exists but is empty (no database/files to check).
|
|
func TestIntegrityChecks_EmptyBeadsDir(t *testing.T) {
|
|
checks := []struct {
|
|
name string
|
|
fn func(string) DoctorCheck
|
|
}{
|
|
{"IDFormat", CheckIDFormat},
|
|
{"DependencyCycles", CheckDependencyCycles},
|
|
{"Tombstones", CheckTombstones},
|
|
{"DeletionsManifest", CheckDeletionsManifest},
|
|
}
|
|
|
|
for _, tc := range checks {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
beadsDir := filepath.Join(tmpDir, ".beads")
|
|
if err := os.Mkdir(beadsDir, 0755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
result := tc.fn(tmpDir)
|
|
|
|
if result.Status != StatusOK {
|
|
t.Errorf("Status = %q, want %q", result.Status, StatusOK)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestCheckDeletionsManifest_LegacyFile tests the specific case where a legacy
|
|
// deletions.jsonl file exists and should trigger a warning.
|
|
func TestCheckDeletionsManifest_LegacyFile(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
beadsDir := filepath.Join(tmpDir, ".beads")
|
|
if err := os.Mkdir(beadsDir, 0755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Create a deletions.jsonl file
|
|
deletionsPath := filepath.Join(beadsDir, "deletions.jsonl")
|
|
if err := os.WriteFile(deletionsPath, []byte(`{"id":"test-1"}`), 0644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
check := CheckDeletionsManifest(tmpDir)
|
|
|
|
// Should warn about legacy deletions file
|
|
if check.Status != StatusWarning {
|
|
t.Errorf("Status = %q, want %q", check.Status, StatusWarning)
|
|
}
|
|
}
|