Skip to content

Commit 14bf72f

Browse files
committed
test: expand P0/P1 coverage for installer, brew, npm, and cli
Add deterministic command stubs for brew/npm and validate CLI pre-run config handling. Improves installer coverage and bumps total coverage to 27.8%.
1 parent 61fd500 commit 14bf72f

6 files changed

Lines changed: 808 additions & 0 deletions

File tree

internal/brew/brew_command_test.go

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package brew
2+
3+
import (
4+
"os"
5+
"path/filepath"
6+
"testing"
7+
8+
"github.com/stretchr/testify/assert"
9+
"github.com/stretchr/testify/require"
10+
)
11+
12+
func setupFakeBrew(t *testing.T, script string) {
13+
t.Helper()
14+
tmpDir := t.TempDir()
15+
brewPath := filepath.Join(tmpDir, "brew")
16+
require.NoError(t, os.WriteFile(brewPath, []byte(script), 0755))
17+
originalPath := os.Getenv("PATH")
18+
t.Setenv("PATH", tmpDir+string(os.PathListSeparator)+originalPath)
19+
}
20+
21+
func TestGetInstalledPackages_ParsesOutput(t *testing.T) {
22+
setupFakeBrew(t, "#!/bin/sh\n"+
23+
"if [ \"$1\" = \"list\" ] && [ \"$2\" = \"--formula\" ]; then\n"+
24+
" echo git\n"+
25+
" echo curl\n"+
26+
" exit 0\n"+
27+
"fi\n"+
28+
"if [ \"$1\" = \"list\" ] && [ \"$2\" = \"--cask\" ]; then\n"+
29+
" echo firefox\n"+
30+
" exit 0\n"+
31+
"fi\n"+
32+
"exit 0\n")
33+
34+
formulae, casks, err := GetInstalledPackages()
35+
require.NoError(t, err)
36+
assert.True(t, formulae["git"])
37+
assert.True(t, formulae["curl"])
38+
assert.True(t, casks["firefox"])
39+
}
40+
41+
func TestListOutdated_ParsesJSON(t *testing.T) {
42+
setupFakeBrew(t, "#!/bin/sh\n"+
43+
"if [ \"$1\" = \"outdated\" ] && [ \"$2\" = \"--json\" ]; then\n"+
44+
" cat <<'EOF'\n"+
45+
"{\"formulae\":[{\"name\":\"git\",\"installed_versions\":[\"2.0\"],\"current_version\":\"2.1\"}],\"casks\":[{\"name\":\"firefox\",\"installed_versions\":[\"1.0\"],\"current_version\":\"2.0\"}]}\n"+
46+
"EOF\n"+
47+
" exit 0\n"+
48+
"fi\n"+
49+
"exit 0\n")
50+
51+
outdated, err := ListOutdated()
52+
require.NoError(t, err)
53+
assert.Len(t, outdated, 2)
54+
assert.Equal(t, "git", outdated[0].Name)
55+
assert.Equal(t, "firefox (cask)", outdated[1].Name)
56+
}
57+
58+
func TestDoctorDiagnose_Suggestions(t *testing.T) {
59+
setupFakeBrew(t, "#!/bin/sh\n"+
60+
"if [ \"$1\" = \"doctor\" ]; then\n"+
61+
" echo 'Warning: unbrewed header files were found'\n"+
62+
" echo 'Warning: broken symlinks detected'\n"+
63+
" exit 0\n"+
64+
"fi\n"+
65+
"exit 0\n")
66+
67+
suggestions, err := DoctorDiagnose()
68+
require.NoError(t, err)
69+
assert.Contains(t, suggestions, "Run: sudo rm -rf /usr/local/include")
70+
assert.Contains(t, suggestions, "Run: brew cleanup --prune=all")
71+
}
72+
73+
func TestUpdateAndCleanup_UsesBrew(t *testing.T) {
74+
setupFakeBrew(t, "#!/bin/sh\n"+
75+
"if [ \"$1\" = \"update\" ]; then\n"+
76+
" exit 0\n"+
77+
"fi\n"+
78+
"if [ \"$1\" = \"upgrade\" ]; then\n"+
79+
" exit 0\n"+
80+
"fi\n"+
81+
"if [ \"$1\" = \"cleanup\" ]; then\n"+
82+
" exit 0\n"+
83+
"fi\n"+
84+
"exit 0\n")
85+
86+
err := Update(false)
87+
assert.NoError(t, err)
88+
89+
err = Cleanup()
90+
assert.NoError(t, err)
91+
}

internal/brew/brew_test.go

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package brew
22

33
import (
4+
"strings"
45
"testing"
56

67
"github.com/stretchr/testify/assert"
@@ -81,3 +82,133 @@ func TestParseBrewError(t *testing.T) {
8182
})
8283
}
8384
}
85+
86+
func TestParseBrewError_LongErrorLine(t *testing.T) {
87+
longLine := "Error: " + strings.Repeat("x", 100)
88+
result := parseBrewError(longLine)
89+
assert.LessOrEqual(t, len(result), 63)
90+
assert.True(t, strings.HasSuffix(result, "..."))
91+
}
92+
93+
func TestParseBrewError_EmptyOutput(t *testing.T) {
94+
result := parseBrewError("")
95+
assert.Equal(t, "unknown error", result)
96+
}
97+
98+
func TestIsRetryableError(t *testing.T) {
99+
tests := []struct {
100+
name string
101+
errMsg string
102+
expected bool
103+
}{
104+
{"connection_timed_out", "connection timed out", true},
105+
{"connection_refused", "connection refused", true},
106+
{"no_internet", "no internet connection", true},
107+
{"download_corrupted", "download corrupted", true},
108+
{"already_running", "already running", true},
109+
{"cannot_download", "Cannot download non-corrupt file", true},
110+
{"signature_mismatch", "signature mismatch detected", true},
111+
{"package_not_found", "package not found", false},
112+
{"permission_denied", "permission denied", false},
113+
{"disk_full", "disk full", false},
114+
{"dependency_error", "dependency error", false},
115+
{"unknown_error", "unknown error", false},
116+
{"empty_string", "", false},
117+
}
118+
119+
for _, tt := range tests {
120+
t.Run(tt.name, func(t *testing.T) {
121+
result := isRetryableError(tt.errMsg)
122+
assert.Equal(t, tt.expected, result)
123+
})
124+
}
125+
}
126+
127+
func TestInstall_EmptyPackages(t *testing.T) {
128+
err := Install([]string{}, false)
129+
assert.NoError(t, err)
130+
}
131+
132+
func TestInstall_DryRun(t *testing.T) {
133+
err := Install([]string{"git", "curl", "jq"}, true)
134+
assert.NoError(t, err)
135+
}
136+
137+
func TestInstallCask_EmptyPackages(t *testing.T) {
138+
err := InstallCask([]string{}, false)
139+
assert.NoError(t, err)
140+
}
141+
142+
func TestInstallCask_DryRun(t *testing.T) {
143+
err := InstallCask([]string{"firefox", "visual-studio-code"}, true)
144+
assert.NoError(t, err)
145+
}
146+
147+
func TestInstallTaps_EmptyTaps(t *testing.T) {
148+
err := InstallTaps([]string{}, false)
149+
assert.NoError(t, err)
150+
}
151+
152+
func TestInstallTaps_DryRun(t *testing.T) {
153+
err := InstallTaps([]string{"homebrew/cask-fonts", "hashicorp/tap"}, true)
154+
assert.NoError(t, err)
155+
}
156+
157+
func TestInstallWithProgress_EmptyPackages(t *testing.T) {
158+
err := InstallWithProgress([]string{}, []string{}, false)
159+
assert.NoError(t, err)
160+
}
161+
162+
func TestInstallWithProgress_DryRun(t *testing.T) {
163+
err := InstallWithProgress([]string{"git", "curl"}, []string{"firefox"}, true)
164+
assert.NoError(t, err)
165+
}
166+
167+
func TestUpdate_DryRun(t *testing.T) {
168+
err := Update(true)
169+
assert.NoError(t, err)
170+
}
171+
172+
func TestCheckDiskSpace(t *testing.T) {
173+
gb, err := CheckDiskSpace()
174+
assert.NoError(t, err)
175+
assert.Greater(t, gb, 0.0)
176+
}
177+
178+
func TestOutdatedPackageStruct(t *testing.T) {
179+
pkg := OutdatedPackage{
180+
Name: "git",
181+
Current: "2.40.0",
182+
Latest: "2.42.0",
183+
}
184+
assert.Equal(t, "git", pkg.Name)
185+
assert.Equal(t, "2.40.0", pkg.Current)
186+
assert.Equal(t, "2.42.0", pkg.Latest)
187+
}
188+
189+
func TestHandleFailedJobs_Empty(t *testing.T) {
190+
handleFailedJobs(nil)
191+
handleFailedJobs([]failedJob{})
192+
}
193+
194+
func TestHandleFailedJobs_WithFailures(t *testing.T) {
195+
failed := []failedJob{
196+
{installJob: installJob{name: "pkg1", isCask: false}, errMsg: "not found"},
197+
{installJob: installJob{name: "pkg2", isCask: true}, errMsg: ""},
198+
}
199+
handleFailedJobs(failed)
200+
}
201+
202+
func TestRunParallelInstallWithProgress_EmptyPkgs(t *testing.T) {
203+
result := runParallelInstallWithProgress(nil, nil)
204+
assert.Nil(t, result)
205+
}
206+
207+
func TestIsInstalled(t *testing.T) {
208+
result := IsInstalled()
209+
assert.IsType(t, true, result)
210+
}
211+
212+
func TestMaxWorkersConstant(t *testing.T) {
213+
assert.Equal(t, 1, maxWorkers)
214+
}

internal/cli/root_test.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package cli
2+
3+
import (
4+
"encoding/json"
5+
"net/http"
6+
"net/http/httptest"
7+
"testing"
8+
9+
"github.com/openbootdotdev/openboot/internal/config"
10+
"github.com/stretchr/testify/assert"
11+
"github.com/stretchr/testify/require"
12+
)
13+
14+
func TestPersistentPreRunE_SilentEnvOverrides(t *testing.T) {
15+
oldCfg := cfg
16+
cfg = &config.Config{Silent: true}
17+
t.Cleanup(func() { cfg = oldCfg })
18+
19+
t.Setenv("OPENBOOT_GIT_NAME", "Test User")
20+
t.Setenv("OPENBOOT_GIT_EMAIL", "test@example.com")
21+
t.Setenv("OPENBOOT_PRESET", "developer")
22+
23+
err := rootCmd.PersistentPreRunE(rootCmd, []string{})
24+
require.NoError(t, err)
25+
assert.Equal(t, "Test User", cfg.GitName)
26+
assert.Equal(t, "test@example.com", cfg.GitEmail)
27+
assert.Equal(t, "developer", cfg.Preset)
28+
}
29+
30+
func TestPersistentPreRunE_UserFetchesRemoteConfig(t *testing.T) {
31+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
32+
assert.Equal(t, "/testuser/default/config", r.URL.Path)
33+
response := config.RemoteConfig{
34+
Username: "testuser",
35+
Slug: "default",
36+
Preset: "developer",
37+
Packages: []string{"git"},
38+
Casks: []string{"firefox"},
39+
Npm: []string{"typescript"},
40+
}
41+
w.Header().Set("Content-Type", "application/json")
42+
require.NoError(t, json.NewEncoder(w).Encode(response))
43+
}))
44+
defer server.Close()
45+
46+
oldCfg := cfg
47+
cfg = &config.Config{}
48+
t.Cleanup(func() { cfg = oldCfg })
49+
50+
t.Setenv("OPENBOOT_USER", "testuser")
51+
t.Setenv("OPENBOOT_API_URL", server.URL)
52+
t.Setenv("HOME", t.TempDir())
53+
54+
err := rootCmd.PersistentPreRunE(rootCmd, []string{})
55+
require.NoError(t, err)
56+
require.NotNil(t, cfg.RemoteConfig)
57+
assert.Equal(t, "testuser", cfg.User)
58+
assert.Equal(t, "developer", cfg.Preset)
59+
assert.Equal(t, "developer", cfg.RemoteConfig.Preset)
60+
}

0 commit comments

Comments
 (0)