github.com/markusbkk/elvish@v0.0.0-20231204143114-91dc52438621/pkg/cli/modes/navigation_test.go (about) 1 package modes 2 3 import ( 4 "errors" 5 "testing" 6 7 "github.com/markusbkk/elvish/pkg/cli" 8 . "github.com/markusbkk/elvish/pkg/cli/clitest" 9 "github.com/markusbkk/elvish/pkg/cli/lscolors" 10 "github.com/markusbkk/elvish/pkg/cli/term" 11 "github.com/markusbkk/elvish/pkg/cli/tk" 12 "github.com/markusbkk/elvish/pkg/testutil" 13 "github.com/markusbkk/elvish/pkg/ui" 14 ) 15 16 var testDir = testutil.Dir{ 17 "a": "", 18 "d": testutil.Dir{ 19 "d1": "content\td1\nline 2", 20 "d2": testutil.Dir{ 21 "d21": "content d21", 22 "d22": "content d22", 23 "other.png": "", 24 }, 25 "d3": testutil.Dir{}, 26 ".dh": "hidden", 27 }, 28 "f": "", 29 } 30 31 func TestErrorInAscend(t *testing.T) { 32 f := Setup() 33 defer f.Stop() 34 35 c := getTestCursor() 36 c.ascendErr = errors.New("cannot ascend") 37 startNavigation(f.App, NavigationSpec{Cursor: c}) 38 39 f.TTY.Inject(term.K(ui.Left)) 40 f.TestTTYNotes(t, 41 "error: cannot ascend", Styles, 42 "!!!!!!") 43 } 44 45 func TestErrorInDescend(t *testing.T) { 46 f := Setup() 47 defer f.Stop() 48 49 c := getTestCursor() 50 c.descendErr = errors.New("cannot descend") 51 startNavigation(f.App, NavigationSpec{Cursor: c}) 52 53 f.TTY.Inject(term.K(ui.Down)) 54 f.TTY.Inject(term.K(ui.Right)) 55 f.TestTTYNotes(t, 56 "error: cannot descend", Styles, 57 "!!!!!!") 58 } 59 60 func TestErrorInCurrent(t *testing.T) { 61 f := setupNav(t) 62 defer f.Stop() 63 64 c := getTestCursor() 65 c.currentErr = errors.New("ERR") 66 startNavigation(f.App, NavigationSpec{Cursor: c}) 67 68 f.TestTTY(t, 69 "", term.DotHere, "\n", 70 " NAVIGATING \n", Styles, 71 "************ ", 72 " a ERR \n", Styles, 73 " !!!", 74 " d \n", Styles, 75 "////", 76 " f ", 77 ) 78 79 // Test that Right does nothing. 80 f.TTY.Inject(term.K(ui.Right)) 81 // We can't just test that the buffer hasn't changed, because that might 82 // capture the state of the buffer before the Right key is handled. Instead 83 // we inject a key and test the result of that instead, to ensure that the 84 // Right key had no effect. 85 f.TTY.Inject(term.K('x')) 86 f.TestTTY(t, 87 "x", term.DotHere, "\n", 88 " NAVIGATING \n", Styles, 89 "************ ", 90 " a ERR \n", Styles, 91 " !!!", 92 " d \n", Styles, 93 "////", 94 " f ", 95 ) 96 } 97 98 func TestErrorInParent(t *testing.T) { 99 f := setupNav(t) 100 defer f.Stop() 101 102 c := getTestCursor() 103 c.parentErr = errors.New("ERR") 104 startNavigation(f.App, NavigationSpec{Cursor: c}) 105 106 f.TestTTY(t, 107 "", term.DotHere, "\n", 108 " NAVIGATING \n", Styles, 109 "************ ", 110 "ERR d1 content d1\n", Styles, 111 "!!! ++++++++++++++", 112 " d2 line 2\n", Styles, 113 " //////////////", 114 " d3 ", Styles, 115 " //////////////", 116 ) 117 } 118 119 func TestWidthRatio(t *testing.T) { 120 f := setupNav(t) 121 defer f.Stop() 122 123 c := getTestCursor() 124 startNavigation(f.App, NavigationSpec{ 125 Cursor: c, 126 WidthRatio: func() [3]int { return [3]int{1, 1, 1} }, 127 }) 128 129 f.TestTTY(t, 130 "", term.DotHere, "\n", 131 " NAVIGATING \n", Styles, 132 "************ ", 133 " a d1 content d1\n", Styles, 134 " +++++++++++++", 135 " d d2 line 2\n", Styles, 136 "############ /////////////", 137 " f d3 ", Styles, 138 " /////////////", 139 ) 140 } 141 142 func TestGetSelectedName(t *testing.T) { 143 f := Setup() 144 defer f.Stop() 145 146 w := startNavigation(f.App, NavigationSpec{Cursor: getTestCursor()}) 147 148 wantName := "d1" 149 if name := w.SelectedName(); name != wantName { 150 t.Errorf("Got name %q, want %q", name, wantName) 151 } 152 } 153 154 func TestNavigation_FakeFS(t *testing.T) { 155 cursor := getTestCursor() 156 testNavigation(t, cursor) 157 } 158 159 func TestNavigation_RealFS(t *testing.T) { 160 testutil.InTempDir(t) 161 testutil.ApplyDir(testDir) 162 163 testutil.MustChdir("d") 164 testNavigation(t, nil) 165 } 166 167 func testNavigation(t *testing.T, c NavigationCursor) { 168 f := setupNav(t) 169 defer f.Stop() 170 171 w := startNavigation(f.App, NavigationSpec{Cursor: c}) 172 173 // Test initial UI and file preview. 174 // NOTE: Buffers are named after the file that is now being selected. 175 d1Buf := f.MakeBuffer( 176 "", term.DotHere, "\n", 177 " NAVIGATING \n", Styles, 178 "************ ", 179 " a d1 content d1\n", Styles, 180 " ++++++++++++++", 181 " d d2 line 2\n", Styles, 182 "#### //////////////", 183 " f d3 ", Styles, 184 " //////////////", 185 ) 186 f.TTY.TestBuffer(t, d1Buf) 187 188 // Test scrolling of preview. 189 w.ScrollPreview(1) 190 f.App.Redraw() 191 d1Buf2 := f.MakeBuffer( 192 "", term.DotHere, "\n", 193 " NAVIGATING \n", Styles, 194 "************ ", 195 " a d1 line 2 │\n", Styles, 196 " ++++++++++++++ -", 197 " d d2 │\n", Styles, 198 "#### ////////////// -", 199 " f d3 ", Styles, 200 " ////////////// X", 201 ) 202 f.TTY.TestBuffer(t, d1Buf2) 203 204 // Test handling of selection change and directory preview. Also test 205 // LS_COLORS. 206 w.Select(tk.Next) 207 f.App.Redraw() 208 d2Buf := f.MakeBuffer( 209 "", term.DotHere, "\n", 210 " NAVIGATING \n", Styles, 211 "************ ", 212 " a d1 d21 \n", Styles, 213 " ++++++++++++++++++++", 214 " d d2 d22 \n", Styles, 215 "#### ##############", 216 " f d3 other.png ", Styles, 217 " ////////////// !!!!!!!!!!!!!!!!!!!!", 218 ) 219 f.TTY.TestBuffer(t, d2Buf) 220 221 // Test handling of Descend. 222 w.Descend() 223 f.App.Redraw() 224 d21Buf := f.MakeBuffer( 225 "", term.DotHere, "\n", 226 " NAVIGATING \n", Styles, 227 "************ ", 228 " d1 d21 content d21\n", Styles, 229 " ++++++++++++++", 230 " d2 d22 \n", Styles, 231 "####", 232 " d3 other.png ", Styles, 233 "//// !!!!!!!!!!!!!!", 234 ) 235 f.TTY.TestBuffer(t, d21Buf) 236 237 // Test handling of Ascend, and that the current column selects the 238 // directory we just ascended from, thus reverting to wantBuf1. 239 w.Ascend() 240 f.App.Redraw() 241 f.TTY.TestBuffer(t, d2Buf) 242 243 // Test handling of Descend on a regular file, i.e. do nothing. First move 244 // the cursor to d1, which is a regular file. 245 w.Select(tk.Prev) 246 f.App.Redraw() 247 f.TTY.TestBuffer(t, d1Buf) 248 // Now descend, and verify that the buffer has not changed. 249 w.Descend() 250 f.App.Redraw() 251 f.TTY.TestBuffer(t, d1Buf) 252 253 // Test showing hidden. 254 w.MutateShowHidden(func(bool) bool { return true }) 255 f.App.Redraw() 256 f.TestTTY(t, 257 "", term.DotHere, "\n", 258 " NAVIGATING (show hidden) \n", Styles, 259 "************************** ", 260 " a .dh content d1\n", 261 " d d1 line 2\n", Styles, 262 "#### ++++++++++++++", 263 " f d2 \n", Styles, 264 " //////////////", 265 " d3 ", Styles, 266 " //////////////", 267 ) 268 w.MutateShowHidden(func(bool) bool { return false }) 269 270 // Test filtering; current column shows d1, d2, d3 before filtering, and 271 // only shows d2 after filtering. 272 w.MutateFiltering(func(bool) bool { return true }) 273 f.TTY.Inject(term.K('2')) 274 f.TestTTY(t, 275 "\n", 276 " NAVIGATING 2", Styles, 277 "************ ", term.DotHere, "\n", 278 " a d2 d21 \n", Styles, 279 " ############## ++++++++++++++++++++", 280 " d d22 \n", Styles, 281 "####", 282 " f other.png ", Styles, 283 " !!!!!!!!!!!!!!!!!!!!", 284 ) 285 w.MutateFiltering(func(bool) bool { return false }) 286 287 // Now move into d2, and test that the filter has been cleared when 288 // descending. 289 w.Descend() 290 f.App.Redraw() 291 f.TTY.TestBuffer(t, d21Buf) 292 293 // Apply a filter within d2. 294 w.MutateFiltering(func(bool) bool { return true }) 295 f.TTY.Inject(term.K('2')) 296 f.TestTTY(t, 297 "\n", 298 " NAVIGATING 2", Styles, 299 "************ ", term.DotHere, "\n", 300 " d1 d21 content d21\n", Styles, 301 " ++++++++++++++", 302 " d2 d22 \n", Styles, 303 "####", 304 " d3 ", Styles, 305 "////", 306 ) 307 w.MutateFiltering(func(bool) bool { return false }) 308 309 // Ascend, and test that the filter has been cleared again when ascending. 310 w.Ascend() 311 f.App.Redraw() 312 f.TTY.TestBuffer(t, d2Buf) 313 314 // Now move into d3, an empty directory. 315 w.Select(tk.Next) 316 w.Descend() 317 f.App.Redraw() 318 d3NoneBuf := f.MakeBuffer( 319 "", term.DotHere, "\n", 320 " NAVIGATING \n", Styles, 321 "************ ", 322 " d1 \n", 323 " d2 \n", Styles, 324 "////", 325 " d3 ", Styles, 326 "####", 327 ) 328 f.TTY.TestBuffer(t, d3NoneBuf) 329 // Test that selecting the previous does nothing in an empty directory. 330 w.Select(tk.Prev) 331 f.App.Redraw() 332 f.TTY.TestBuffer(t, d3NoneBuf) 333 // Test that selecting the next does nothing in an empty directory. 334 w.Select(tk.Next) 335 f.App.Redraw() 336 f.TTY.TestBuffer(t, d3NoneBuf) 337 // Test that Descend does nothing in an empty directory. 338 w.Descend() 339 f.App.Redraw() 340 f.TTY.TestBuffer(t, d3NoneBuf) 341 } 342 343 func TestNewNavigation_FocusedWidgetNotCodeArea(t *testing.T) { 344 testFocusedWidgetNotCodeArea(t, func(app cli.App) error { 345 _, err := NewNavigation(app, NavigationSpec{}) 346 return err 347 }) 348 } 349 350 func setupNav(c testutil.Cleanuper) *Fixture { 351 lscolors.SetTestLsColors(c) 352 // Use a small TTY size to make the test buffer easier to build. 353 return Setup(WithTTY(func(tty TTYCtrl) { tty.SetSize(6, 40) })) 354 } 355 356 func startNavigation(app cli.App, spec NavigationSpec) Navigation { 357 w, _ := NewNavigation(app, spec) 358 startMode(app, w, nil) 359 return w 360 } 361 362 func getTestCursor() *testCursor { 363 return &testCursor{root: testDir, pwd: []string{"d"}} 364 }