v0.33.2 57f21d6

manager_test.go RawHistoryFolder

1package env_test
2
3import (
4	"context"
5	"os"
6	"os/exec"
7	"testing"
8
9	"github.com/bnema/dumber/internal/infrastructure/env"
10	"github.com/stretchr/testify/assert"
11	"github.com/stretchr/testify/require"
12)
13
14func TestManager_ApplyEnvironment_SkiaEnv(t *testing.T) {
15	// Save original env vars and restore after test
16	origCPU := os.Getenv("WEBKIT_SKIA_CPU_PAINTING_THREADS")
17	origGPU := os.Getenv("WEBKIT_SKIA_GPU_PAINTING_THREADS")
18	origCPURender := os.Getenv("WEBKIT_SKIA_ENABLE_CPU_RENDERING")
19	t.Cleanup(func() {
20		restoreEnv("WEBKIT_SKIA_CPU_PAINTING_THREADS", origCPU)
21		restoreEnv("WEBKIT_SKIA_GPU_PAINTING_THREADS", origGPU)
22		restoreEnv("WEBKIT_SKIA_ENABLE_CPU_RENDERING", origCPURender)
23	})
24
25	tests := []struct {
26		name           string
27		settings       env.RenderingSettings
28		presetEnv      map[string]string
29		expectedVars   map[string]string
30		unexpectedVars []string
31	}{
32		{
33			name: "CPU threads set when > 0",
34			settings: env.RenderingSettings{
35				SkiaCPUPaintingThreads: 4,
36				SkiaGPUPaintingThreads: -1, // unset
37			},
38			expectedVars: map[string]string{
39				"WEBKIT_SKIA_CPU_PAINTING_THREADS": "4",
40			},
41			unexpectedVars: []string{"WEBKIT_SKIA_GPU_PAINTING_THREADS"},
42		},
43		{
44			name: "GPU threads set when >= 0",
45			settings: env.RenderingSettings{
46				SkiaCPUPaintingThreads: 0, // unset
47				SkiaGPUPaintingThreads: 2,
48			},
49			expectedVars: map[string]string{
50				"WEBKIT_SKIA_GPU_PAINTING_THREADS": "2",
51			},
52			unexpectedVars: []string{"WEBKIT_SKIA_CPU_PAINTING_THREADS"},
53		},
54		{
55			name: "GPU threads 0 disables GPU tile painting",
56			settings: env.RenderingSettings{
57				SkiaGPUPaintingThreads: 0,
58			},
59			expectedVars: map[string]string{
60				"WEBKIT_SKIA_GPU_PAINTING_THREADS": "0",
61			},
62		},
63		{
64			name: "CPU rendering enabled",
65			settings: env.RenderingSettings{
66				SkiaEnableCPURendering: true,
67			},
68			expectedVars: map[string]string{
69				"WEBKIT_SKIA_ENABLE_CPU_RENDERING": "1",
70			},
71		},
72		{
73			name: "CPU rendering disabled (default)",
74			settings: env.RenderingSettings{
75				SkiaEnableCPURendering: false,
76			},
77			unexpectedVars: []string{"WEBKIT_SKIA_ENABLE_CPU_RENDERING"},
78		},
79		{
80			name: "does not override existing CPU threads env var",
81			settings: env.RenderingSettings{
82				SkiaCPUPaintingThreads: 8,
83			},
84			presetEnv: map[string]string{
85				"WEBKIT_SKIA_CPU_PAINTING_THREADS": "2",
86			},
87			expectedVars: map[string]string{
88				"WEBKIT_SKIA_CPU_PAINTING_THREADS": "2", // keeps original
89			},
90		},
91		{
92			name: "does not override existing GPU threads env var",
93			settings: env.RenderingSettings{
94				SkiaGPUPaintingThreads: 4,
95			},
96			presetEnv: map[string]string{
97				"WEBKIT_SKIA_GPU_PAINTING_THREADS": "1",
98			},
99			expectedVars: map[string]string{
100				"WEBKIT_SKIA_GPU_PAINTING_THREADS": "1", // keeps original
101			},
102		},
103		{
104			name: "does not override existing CPU rendering env var",
105			settings: env.RenderingSettings{
106				SkiaEnableCPURendering: true,
107			},
108			presetEnv: map[string]string{
109				"WEBKIT_SKIA_ENABLE_CPU_RENDERING": "0",
110			},
111			expectedVars: map[string]string{
112				"WEBKIT_SKIA_ENABLE_CPU_RENDERING": "0", // keeps original
113			},
114		},
115		{
116			name: "all unset by default",
117			settings: env.RenderingSettings{
118				SkiaCPUPaintingThreads: 0,  // unset
119				SkiaGPUPaintingThreads: -1, // unset
120				SkiaEnableCPURendering: false,
121			},
122			unexpectedVars: []string{
123				"WEBKIT_SKIA_CPU_PAINTING_THREADS",
124				"WEBKIT_SKIA_GPU_PAINTING_THREADS",
125				"WEBKIT_SKIA_ENABLE_CPU_RENDERING",
126			},
127		},
128	}
129
130	for _, tt := range tests {
131		t.Run(tt.name, func(t *testing.T) {
132			// Clear env vars before each test
133			os.Unsetenv("WEBKIT_SKIA_CPU_PAINTING_THREADS")
134			os.Unsetenv("WEBKIT_SKIA_GPU_PAINTING_THREADS")
135			os.Unsetenv("WEBKIT_SKIA_ENABLE_CPU_RENDERING")
136
137			// Set any preset env vars
138			for k, v := range tt.presetEnv {
139				os.Setenv(k, v)
140			}
141
142			manager := env.NewManager()
143			ctx := context.Background()
144
145			err := manager.ApplyEnvironment(ctx, tt.settings)
146			require.NoError(t, err)
147
148			// Check expected vars are set correctly
149			for k, v := range tt.expectedVars {
150				actual := os.Getenv(k)
151				assert.Equal(t, v, actual, "env var %s", k)
152			}
153
154			// Check unexpected vars are not set (or were not set by us)
155			appliedVars := manager.GetAppliedVars()
156			for _, k := range tt.unexpectedVars {
157				_, wasApplied := appliedVars[k]
158				if tt.presetEnv[k] == "" {
159					assert.False(t, wasApplied, "env var %s should not be applied", k)
160				}
161			}
162		})
163	}
164}
165
166func restoreEnv(key, value string) {
167	if value == "" {
168		os.Unsetenv(key)
169	} else {
170		os.Setenv(key, value)
171	}
172}
173
174func TestIsFlatpak(t *testing.T) {
175	// IsFlatpak checks for /.flatpak-info file existence
176	// In normal test environment, this should return false
177	result := env.IsFlatpak()
178
179	// We can't easily mock filesystem, so just verify it returns a boolean
180	// and doesn't panic. In CI/dev environment it should be false.
181	assert.False(t, result, "should not detect Flatpak in test environment")
182}
183
184func TestIsPacman(t *testing.T) {
185	// Only run these tests on Arch-based systems with pacman
186	if _, err := os.Stat("/usr/bin/pacman"); os.IsNotExist(err) {
187		t.Skip("pacman not found, skipping Arch-specific tests")
188	}
189
190	tests := []struct {
191		name     string
192		binary   string
193		expected bool
194	}{
195		{
196			name:     "system binary owned by pacman",
197			binary:   "/usr/bin/bash",
198			expected: true, // bash is always installed via pacman on Arch
199		},
200		{
201			name:     "non-existent binary",
202			binary:   "/nonexistent/path/to/binary",
203			expected: false,
204		},
205	}
206
207	for _, tt := range tests {
208		t.Run(tt.name, func(t *testing.T) {
209			// We can't easily test IsPacman directly since it uses os.Executable()
210			// but we can test the underlying pacman -Qo logic with exec.Command
211			cmd := exec.Command("pacman", "-Qo", tt.binary)
212			err := cmd.Run()
213			if tt.expected {
214				assert.NoError(t, err, "pacman should own %s", tt.binary)
215			} else {
216				assert.Error(t, err, "pacman should not own %s", tt.binary)
217			}
218		})
219	}
220}
221
222func TestIsPacman_NonArchSystem(t *testing.T) {
223	// On non-Arch systems, IsPacman should return false (pacman not found)
224	if _, err := os.Stat("/usr/bin/pacman"); err == nil {
225		t.Skip("pacman found, skipping non-Arch test")
226	}
227
228	result := env.IsPacman()
229	assert.False(t, result, "should return false when pacman is not installed")
230}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close