From b4b6a993eac873dc92b850a6acb0dcc28273eb89 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sun, 20 Sep 2026 16:03:05 +0200 Subject: [PATCH] Add a test for following a file into a rename in a collapsed directory When the deletion of the selected file is staged and git then reports it as the old half of a rename whose new half sits in a collapsed directory, the selection is meant to move to the rename, expanding the directory on the way. With gui.showRootItemInFileTree turned on, the directory stays collapsed and the selection lands on it instead. With the option turned off, the directory does expand, but if another file in it sorts before the rename, that file gets selected. Co-Authored-By: Claude Fable 5.1 --- pkg/gui/filetree/file_tree_view_model_test.go | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/pkg/gui/filetree/file_tree_view_model_test.go b/pkg/gui/filetree/file_tree_view_model_test.go index fcc24a1b4..d05cf7e93 100644 --- a/pkg/gui/filetree/file_tree_view_model_test.go +++ b/pkg/gui/filetree/file_tree_view_model_test.go @@ -78,3 +78,57 @@ func TestSetTreeSelectsNewFileWhenSelectedRenameSplits(t *testing.T) { }) } } + +func TestSetTreeFollowsRenameIntoCollapsedDir(t *testing.T) { + scenarios := []struct { + name string + showRootItem bool + expectedPath string + }{ + { + name: "with root item", + showRootItem: true, + /* EXPECTED: + expectedPath: "a/new.go", + ACTUAL: */ + expectedPath: "a", + }, + { + name: "without root item", + showRootItem: false, + /* EXPECTED: + expectedPath: "a/new.go", + ACTUAL: */ + expectedPath: "a/b.go", + }, + } + + for _, s := range scenarios { + t.Run(s.name, func(t *testing.T) { + userConfig := config.GetDefaultConfig() + userConfig.Gui.ShowRootItemInFileTree = s.showRootItem + cmn := common.NewDummyCommonWithUserConfigAndAppState(userConfig, nil) + + files := []*models.File{ + {Path: "a/b.go"}, + {Path: "a/new.go"}, + {Path: "old.go"}, + } + viewModel := NewFileTreeViewModel(func() []*models.File { return files }, cmn, true) + viewModel.SetTree() + viewModel.ToggleCollapsed(InternalTreePathForFilePath("a", s.showRootItem)) + idx, found := viewModel.GetIndexForPath(InternalTreePathForFilePath("old.go", s.showRootItem)) + assert.True(t, found) + viewModel.SetSelection(idx) + + // staging the deletion of old.go turns it into the old half of a rename + files = []*models.File{ + {Path: "a/b.go"}, + {Path: "a/new.go", PreviousPath: "old.go"}, + } + viewModel.SetTree() + + assert.Equal(t, s.expectedPath, viewModel.GetSelectedPath()) + }) + } +}