Skip to content

Commit f8f7b32

Browse files
committed
test: Add tests for config.go
1 parent 4b51527 commit f8f7b32

File tree

1 file changed

+239
-0
lines changed

1 file changed

+239
-0
lines changed

config/config_test.go

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
package config
2+
3+
import (
4+
"claude-squad/log"
5+
"os"
6+
"path/filepath"
7+
"regexp"
8+
"strings"
9+
"testing"
10+
11+
"github.com/stretchr/testify/assert"
12+
"github.com/stretchr/testify/require"
13+
)
14+
15+
// TestMain runs before all tests to set up the test environment
16+
func TestMain(m *testing.M) {
17+
// Initialize the logger before any tests run
18+
log.Initialize(false)
19+
defer log.Close()
20+
21+
exitCode := m.Run()
22+
os.Exit(exitCode)
23+
}
24+
25+
func TestGetClaudeCommand(t *testing.T) {
26+
originalShell := os.Getenv("SHELL")
27+
originalPath := os.Getenv("PATH")
28+
defer func() {
29+
os.Setenv("SHELL", originalShell)
30+
os.Setenv("PATH", originalPath)
31+
}()
32+
33+
t.Run("finds claude in PATH", func(t *testing.T) {
34+
// Create a temporary directory with a mock claude executable
35+
tempDir := t.TempDir()
36+
claudePath := filepath.Join(tempDir, "claude")
37+
38+
// Create a mock executable
39+
err := os.WriteFile(claudePath, []byte("#!/bin/bash\necho 'mock claude'"), 0755)
40+
require.NoError(t, err)
41+
42+
// Set PATH to include our temp directory
43+
os.Setenv("PATH", tempDir+":"+originalPath)
44+
os.Setenv("SHELL", "/bin/bash")
45+
46+
result, err := GetClaudeCommand()
47+
48+
assert.NoError(t, err)
49+
assert.True(t, strings.Contains(result, "claude"))
50+
})
51+
52+
t.Run("handles missing claude command", func(t *testing.T) {
53+
// Set PATH to a directory that doesn't contain claude
54+
tempDir := t.TempDir()
55+
os.Setenv("PATH", tempDir)
56+
os.Setenv("SHELL", "/bin/bash")
57+
58+
result, err := GetClaudeCommand()
59+
60+
assert.Error(t, err)
61+
assert.Equal(t, "", result)
62+
assert.Contains(t, err.Error(), "claude command not found")
63+
})
64+
65+
t.Run("handles empty SHELL environment", func(t *testing.T) {
66+
// Create a temporary directory with a mock claude executable
67+
tempDir := t.TempDir()
68+
claudePath := filepath.Join(tempDir, "claude")
69+
70+
// Create a mock executable
71+
err := os.WriteFile(claudePath, []byte("#!/bin/bash\necho 'mock claude'"), 0755)
72+
require.NoError(t, err)
73+
74+
// Set PATH and unset SHELL
75+
os.Setenv("PATH", tempDir+":"+originalPath)
76+
os.Unsetenv("SHELL")
77+
78+
result, err := GetClaudeCommand()
79+
80+
assert.NoError(t, err)
81+
assert.True(t, strings.Contains(result, "claude"))
82+
})
83+
84+
t.Run("handles alias parsing", func(t *testing.T) {
85+
// Test core alias formats
86+
aliasRegex := regexp.MustCompile(`(?:aliased to|->|=)\s*([^\s]+)`)
87+
88+
// Standard alias format
89+
output := "claude: aliased to /usr/local/bin/claude"
90+
matches := aliasRegex.FindStringSubmatch(output)
91+
assert.Len(t, matches, 2)
92+
assert.Equal(t, "/usr/local/bin/claude", matches[1])
93+
94+
// Direct path (no alias)
95+
output = "/usr/local/bin/claude"
96+
matches = aliasRegex.FindStringSubmatch(output)
97+
assert.Len(t, matches, 0)
98+
})
99+
}
100+
101+
func TestDefaultConfig(t *testing.T) {
102+
t.Run("creates config with default values", func(t *testing.T) {
103+
config := DefaultConfig()
104+
105+
assert.NotNil(t, config)
106+
assert.NotEmpty(t, config.DefaultProgram)
107+
assert.False(t, config.AutoYes)
108+
assert.Equal(t, 1000, config.DaemonPollInterval)
109+
assert.NotEmpty(t, config.BranchPrefix)
110+
assert.True(t, strings.HasSuffix(config.BranchPrefix, "/"))
111+
})
112+
113+
}
114+
115+
func TestGetConfigDir(t *testing.T) {
116+
t.Run("returns valid config directory", func(t *testing.T) {
117+
configDir, err := GetConfigDir()
118+
119+
assert.NoError(t, err)
120+
assert.NotEmpty(t, configDir)
121+
assert.True(t, strings.HasSuffix(configDir, ".claude-squad"))
122+
123+
// Verify it's an absolute path
124+
assert.True(t, filepath.IsAbs(configDir))
125+
})
126+
}
127+
128+
func TestLoadConfig(t *testing.T) {
129+
t.Run("returns default config when file doesn't exist", func(t *testing.T) {
130+
// Use a temporary home directory to avoid interfering with real config
131+
originalHome := os.Getenv("HOME")
132+
tempHome := t.TempDir()
133+
os.Setenv("HOME", tempHome)
134+
defer os.Setenv("HOME", originalHome)
135+
136+
config := LoadConfig()
137+
138+
assert.NotNil(t, config)
139+
assert.NotEmpty(t, config.DefaultProgram)
140+
assert.False(t, config.AutoYes)
141+
assert.Equal(t, 1000, config.DaemonPollInterval)
142+
assert.NotEmpty(t, config.BranchPrefix)
143+
})
144+
145+
t.Run("loads valid config file", func(t *testing.T) {
146+
// Create a temporary config directory
147+
tempHome := t.TempDir()
148+
configDir := filepath.Join(tempHome, ".claude-squad")
149+
err := os.MkdirAll(configDir, 0755)
150+
require.NoError(t, err)
151+
152+
// Create a test config file
153+
configPath := filepath.Join(configDir, ConfigFileName)
154+
configContent := `{
155+
"default_program": "test-claude",
156+
"auto_yes": true,
157+
"daemon_poll_interval": 2000,
158+
"branch_prefix": "test/"
159+
}`
160+
err = os.WriteFile(configPath, []byte(configContent), 0644)
161+
require.NoError(t, err)
162+
163+
// Override HOME environment
164+
originalHome := os.Getenv("HOME")
165+
os.Setenv("HOME", tempHome)
166+
defer os.Setenv("HOME", originalHome)
167+
168+
config := LoadConfig()
169+
170+
assert.NotNil(t, config)
171+
assert.Equal(t, "test-claude", config.DefaultProgram)
172+
assert.True(t, config.AutoYes)
173+
assert.Equal(t, 2000, config.DaemonPollInterval)
174+
assert.Equal(t, "test/", config.BranchPrefix)
175+
})
176+
177+
t.Run("returns default config on invalid JSON", func(t *testing.T) {
178+
// Create a temporary config directory
179+
tempHome := t.TempDir()
180+
configDir := filepath.Join(tempHome, ".claude-squad")
181+
err := os.MkdirAll(configDir, 0755)
182+
require.NoError(t, err)
183+
184+
// Create an invalid config file
185+
configPath := filepath.Join(configDir, ConfigFileName)
186+
invalidContent := `{"invalid": json content}`
187+
err = os.WriteFile(configPath, []byte(invalidContent), 0644)
188+
require.NoError(t, err)
189+
190+
// Override HOME environment
191+
originalHome := os.Getenv("HOME")
192+
os.Setenv("HOME", tempHome)
193+
defer os.Setenv("HOME", originalHome)
194+
195+
config := LoadConfig()
196+
197+
// Should return default config when JSON is invalid
198+
assert.NotNil(t, config)
199+
assert.NotEmpty(t, config.DefaultProgram)
200+
assert.False(t, config.AutoYes) // Default value
201+
assert.Equal(t, 1000, config.DaemonPollInterval) // Default value
202+
})
203+
}
204+
205+
func TestSaveConfig(t *testing.T) {
206+
t.Run("saves config to file", func(t *testing.T) {
207+
// Create a temporary config directory
208+
tempHome := t.TempDir()
209+
210+
// Override HOME environment
211+
originalHome := os.Getenv("HOME")
212+
os.Setenv("HOME", tempHome)
213+
defer os.Setenv("HOME", originalHome)
214+
215+
// Create a test config
216+
testConfig := &Config{
217+
DefaultProgram: "test-program",
218+
AutoYes: true,
219+
DaemonPollInterval: 3000,
220+
BranchPrefix: "test-branch/",
221+
}
222+
223+
err := SaveConfig(testConfig)
224+
assert.NoError(t, err)
225+
226+
// Verify the file was created
227+
configDir := filepath.Join(tempHome, ".claude-squad")
228+
configPath := filepath.Join(configDir, ConfigFileName)
229+
230+
assert.FileExists(t, configPath)
231+
232+
// Load and verify the content
233+
loadedConfig := LoadConfig()
234+
assert.Equal(t, testConfig.DefaultProgram, loadedConfig.DefaultProgram)
235+
assert.Equal(t, testConfig.AutoYes, loadedConfig.AutoYes)
236+
assert.Equal(t, testConfig.DaemonPollInterval, loadedConfig.DaemonPollInterval)
237+
assert.Equal(t, testConfig.BranchPrefix, loadedConfig.BranchPrefix)
238+
})
239+
}

0 commit comments

Comments
 (0)