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  }