Skip to content

Commit 7f349f9

Browse files
lazysegtreeclaudeyorukot
authored
feat: Zoxide tests (#1042)
- Replace all instances of 'github.com/lazysegtree/go-zoxide' imports with 'zoxidelib' alias for consistency across codebase - Add comprehensive zoxide UI navigation test that types "dir2" to search and presses Enter to navigate - Fix zoxide modal close behavior by adding m.Close() call in handleConfirm action - Add GetResults() method to zoxide UI component for test access - Create defaultTestModelWithZClient() helper function for zoxide testing --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: yorukot <107802416+yorukot@users.noreply.github.com>
1 parent 9272b00 commit 7f349f9

File tree

9 files changed

+112
-22
lines changed

9 files changed

+112
-22
lines changed

.github/workflows/superfile-build-test.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,12 @@ jobs:
2020
steps:
2121
- name: Checkout repository
2222
uses: actions/checkout@v5
23-
- name: Setup exiftool (only on linux)
23+
- name: Setup dependencies (only on linux)
2424
if: runner.os == 'Linux'
25-
run: sudo apt-get update && sudo apt-get install -y exiftool
25+
run: |
26+
sudo apt-get update
27+
sudo apt-get install -y exiftool
28+
curl -sS https://raw.githubusercontent.com/ajeetdsouza/zoxide/main/install.sh | bash
2629
2730
- name: Set up Go
2831
uses: actions/setup-go@v5

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ require (
1313
github.com/charmbracelet/x/ansi v0.9.3
1414
github.com/fatih/color v1.18.0
1515
github.com/hymkor/trash-go v0.2.0
16-
github.com/lazysegtree/go-zoxide v0.0.1
16+
github.com/lazysegtree/go-zoxide v0.1.0
1717
github.com/lithammer/shortuuid v3.0.0+incompatible
1818
github.com/muesli/termenv v0.16.0
1919
github.com/reinhrst/fzf-lib v0.9.0

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
143143
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
144144
github.com/lazysegtree/go-zoxide v0.0.1 h1:PG8asMMqetoxXXfLGTvgzbWHVGybioeJpGm91mhbNoc=
145145
github.com/lazysegtree/go-zoxide v0.0.1/go.mod h1:C1K2SDM4iHkQeFVrWBiRX3tU9jpAz6BrnoHQYSiHZl0=
146+
github.com/lazysegtree/go-zoxide v0.1.0 h1:gL11AWS9fJDuB7FYxsh+ohf8ozMXeK31E/PC6f9jNBc=
147+
github.com/lazysegtree/go-zoxide v0.1.0/go.mod h1:C1K2SDM4iHkQeFVrWBiRX3tU9jpAz6BrnoHQYSiHZl0=
146148
github.com/lithammer/shortuuid v3.0.0+incompatible h1:NcD0xWW/MZYXEHa6ITy6kaXN5nwm/V115vj2YXfhS0w=
147149
github.com/lithammer/shortuuid v3.0.0+incompatible/go.mod h1:FR74pbAuElzOUuenUHTK2Tciko1/vKuIKS9dSkDrA4w=
148150
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=

gomod2nix.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,8 @@ schema = 3
101101
version = "v1.16.3"
102102
hash = "sha256-dU0OgO5afQ1z5s83Y3w8Bg0ftvg+ikWbktUACEgY3OQ="
103103
[mod."github.com/lazysegtree/go-zoxide"]
104-
version = "v0.0.1"
105-
hash = "sha256-pBZ6tOqhYe2ogHyFmP/7R4hc4yfJ7I9hk2D+gT14v4o="
104+
version = "v0.1.0"
105+
hash = "sha256-PKEV+zCKf/7MsFAMMctL/pFSnEsri1yS8Bzxcj1dLWE="
106106
[mod."github.com/lithammer/shortuuid"]
107107
version = "v3.0.0+incompatible"
108108
hash = "sha256-dD6ArCHGnpo84RBy6SI2kUjMqHS4IZU+K+DgAgmRakY="

src/internal/config_function.go

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import (
66
"reflect"
77
"runtime"
88

9-
"github.com/lazysegtree/go-zoxide"
9+
zoxidelib "github.com/lazysegtree/go-zoxide"
1010

1111
"github.com/yorukot/superfile/src/internal/ui/processbar"
1212
"github.com/yorukot/superfile/src/internal/ui/rendering"
@@ -25,7 +25,7 @@ import (
2525

2626
// This is the only usecase of named returns, distinguish between multiple return values
2727
func initialConfig(firstFilePanelDirs []string) (toggleDotFile bool, //nolint: nonamedreturns // See above
28-
toggleFooter bool, zClient *zoxide.Client) {
28+
toggleFooter bool, zClient *zoxidelib.Client) {
2929
// Open log stream
3030
file, err := os.OpenFile(variable.LogFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
3131

@@ -73,7 +73,7 @@ func initialConfig(firstFilePanelDirs []string) (toggleDotFile bool, //nolint: n
7373
}
7474

7575
if common.Config.ZoxideSupport {
76-
zClient, err = zoxide.New()
76+
zClient, err = zoxidelib.New()
7777
if err != nil {
7878
slog.Error("Error initializing zoxide client", "error", err)
7979
}
@@ -90,27 +90,31 @@ func initialConfig(firstFilePanelDirs []string) (toggleDotFile bool, //nolint: n
9090
return toggleDotFile, toggleFooter, zClient
9191
}
9292

93-
func updateFirstFilePanelDirs(firstFilePanelDirs []string, cwd string, zClient *zoxide.Client) {
93+
func updateFirstFilePanelDirs(firstFilePanelDirs []string, cwd string, zClient *zoxidelib.Client) {
9494
for i := range firstFilePanelDirs {
9595
if firstFilePanelDirs[i] == "" {
9696
firstFilePanelDirs[i] = common.Config.DefaultDirectory
9797
}
98+
originalPath := firstFilePanelDirs[i]
99+
firstFilePanelDirs[i] = utils.ResolveAbsPath(cwd, firstFilePanelDirs[i])
98100

99-
if common.Config.ZoxideSupport && zClient != nil {
100-
path, err := zClient.Query(firstFilePanelDirs[i])
101-
if err == nil && path != "" {
102-
firstFilePanelDirs[i] = path
103-
} else {
104-
slog.Error("Zoxide execution error", "path", path, "error", err)
105-
firstFilePanelDirs[i] = utils.ResolveAbsPath(cwd, firstFilePanelDirs[i])
106-
}
107-
} else {
108-
firstFilePanelDirs[i] = utils.ResolveAbsPath(cwd, firstFilePanelDirs[i])
109-
}
110-
// In case of unexpected path error, fallback to home dir
111101
if _, err := os.Stat(firstFilePanelDirs[i]); err != nil {
112102
slog.Error("cannot get stats for firstFilePanelDir", "error", err)
113-
firstFilePanelDirs[i] = variable.HomeDir
103+
// In case the path provided did not exist, use zoxide query
104+
// else, fallback to home dir
105+
if common.Config.ZoxideSupport && zClient != nil {
106+
path, err := zClient.Query(originalPath)
107+
slog.Error("Zoxide execution error", "path", path, "originalPath", originalPath, "error", err)
108+
109+
if err == nil && path != "" {
110+
firstFilePanelDirs[i] = path
111+
} else {
112+
slog.Error("Zoxide execution error", "path", path, "originalPath", originalPath, "error", err)
113+
firstFilePanelDirs[i] = variable.HomeDir
114+
}
115+
} else {
116+
firstFilePanelDirs[i] = variable.HomeDir
117+
}
114118
}
115119
}
116120
}

src/internal/model_test.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ import (
55
"fmt"
66
"os"
77
"path/filepath"
8+
"runtime"
89
"testing"
910

11+
zoxidelib "github.com/lazysegtree/go-zoxide"
1012
"github.com/stretchr/testify/assert"
1113
"github.com/stretchr/testify/require"
1214

@@ -245,3 +247,69 @@ func TestChooserFile(t *testing.T) {
245247
})
246248
}
247249
}
250+
251+
func TestZoxide(t *testing.T) {
252+
zoxideDataDir := t.TempDir()
253+
zClient, err := zoxidelib.New(zoxidelib.WithDataDir(zoxideDataDir))
254+
if err != nil {
255+
if runtime.GOOS != utils.OsLinux {
256+
t.Skipf("Skipping zoxide tests in non-Linux because zoxide client cannot be initialized")
257+
} else {
258+
t.Fatalf("zoxide initialization failed")
259+
}
260+
}
261+
262+
originalZoxideSupport := common.Config.ZoxideSupport
263+
defer func() {
264+
common.Config.ZoxideSupport = originalZoxideSupport
265+
}()
266+
267+
curTestDir := filepath.Join(testDir, "TestZoxide")
268+
dir1 := filepath.Join(curTestDir, "dir1")
269+
dir2 := filepath.Join(curTestDir, "dir2")
270+
dir3 := filepath.Join(curTestDir, "dir3")
271+
utils.SetupDirectories(t, curTestDir, dir1, dir2, dir3)
272+
273+
t.Run("Zoxide tracking and navigation", func(t *testing.T) {
274+
common.Config.ZoxideSupport = true
275+
m := defaultTestModelWithZClient(zClient, dir1)
276+
277+
err := m.updateCurrentFilePanelDir(dir2)
278+
require.NoError(t, err, "Failed to navigate to dir2")
279+
assert.Equal(t, dir2, m.getFocusedFilePanel().location, "Should be in dir2 after navigation")
280+
281+
err = m.updateCurrentFilePanelDir(dir3)
282+
require.NoError(t, err, "Failed to navigate to dir3")
283+
assert.Equal(t, dir3, m.getFocusedFilePanel().location, "Should be in dir3 after navigation")
284+
285+
TeaUpdateWithErrCheck(m, utils.TeaRuneKeyMsg(common.Hotkeys.OpenZoxide[0]))
286+
assert.True(t, m.zoxideModal.IsOpen(), "Zoxide modal should open when pressing 'z' key")
287+
288+
// Type "dir2" to search for it
289+
for _, char := range "dir2" {
290+
TeaUpdateWithErrCheck(m, utils.TeaRuneKeyMsg(string(char)))
291+
}
292+
293+
results := m.zoxideModal.GetResults()
294+
assert.GreaterOrEqual(t, len(results), 1, "Should have at least 1 directory found by zoxide UI search")
295+
296+
resultPaths := make([]string, len(results))
297+
for i, result := range results {
298+
resultPaths[i] = result.Path
299+
}
300+
assert.Contains(t, resultPaths, dir2, "dir2 should be found by zoxide UI search")
301+
302+
// Press enter to navigate to dir2
303+
TeaUpdateWithErrCheck(m, utils.TeaRuneKeyMsg(common.Hotkeys.ConfirmTyping[0]))
304+
assert.False(t, m.zoxideModal.IsOpen(), "Zoxide modal should close after navigation")
305+
assert.Equal(t, dir2, m.getFocusedFilePanel().location, "Should navigate back to dir2 after zoxide selection")
306+
})
307+
308+
t.Run("Zoxide disabled shows no results", func(t *testing.T) {
309+
common.Config.ZoxideSupport = false
310+
m := defaultTestModelWithZClient(zClient, dir1)
311+
312+
TeaUpdateWithErrCheck(m, utils.TeaRuneKeyMsg(common.Hotkeys.OpenZoxide[0]))
313+
assert.True(t, m.zoxideModal.IsOpen(), "Zoxide modal should open even when ZoxideSupport is disabled")
314+
})
315+
}

src/internal/test_utils.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"time"
88

99
tea "github.com/charmbracelet/bubbletea"
10+
zoxidelib "github.com/lazysegtree/go-zoxide"
1011
"github.com/stretchr/testify/assert"
1112
"github.com/stretchr/testify/require"
1213

@@ -26,6 +27,13 @@ func defaultTestModel(dirs ...string) *model {
2627
return m
2728
}
2829

30+
func defaultTestModelWithZClient(zClient *zoxidelib.Client, dirs ...string) *model {
31+
m := defaultModelConfig(false, false, false, dirs, zClient)
32+
m.disableMetatdata = true
33+
_, _ = TeaUpdate(m, tea.WindowSizeMsg{Width: 2 * common.MinimumWidth, Height: 2 * common.MinimumHeight})
34+
return m
35+
}
36+
2937
// Helper function to setup panel mode and selection
3038
func setupPanelModeAndSelection(t *testing.T, m *model, useSelectMode bool, itemName string, selectedItems []string) {
3139
t.Helper()

src/internal/ui/zoxide/model.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ func (m *Model) HandleUpdate(msg tea.Msg) (common.ModelAction, tea.Cmd) {
6060
switch {
6161
case slices.Contains(common.Hotkeys.ConfirmTyping, msg.String()):
6262
action = m.handleConfirm()
63+
m.Close()
6364
case slices.Contains(common.Hotkeys.CancelTyping, msg.String()):
6465
m.Close()
6566
case slices.Contains(common.Hotkeys.ListUp, msg.String()):

src/internal/ui/zoxide/utils.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,7 @@ func (m *Model) SetMaxHeight(maxHeight int) {
5252
}
5353
m.maxHeight = maxHeight
5454
}
55+
56+
func (m *Model) GetResults() []zoxidelib.Result {
57+
return m.results
58+
}

0 commit comments

Comments
 (0)