navigation_wrap_test.go

  1package tui
  2
  3import (
  4	"os"
  5	"path/filepath"
  6	"testing"
  7
  8	tea "charm.land/bubbletea/v2"
  9	"github.com/floatpane/matcha/config"
 10	"github.com/floatpane/matcha/theme"
 11)
 12
 13func TestSettingsNavigationWraps(t *testing.T) {
 14	settings := NewSettings(&config.Config{
 15		Accounts: []config.Account{
 16			{ID: "account-1", Email: "one@example.com"},
 17			{ID: "account-2", Email: "two@example.com"},
 18		},
 19		MailingLists: []config.MailingList{
 20			{Name: "List One"},
 21			{Name: "List Two"},
 22		},
 23	})
 24
 25	t.Run("menu", func(t *testing.T) {
 26		settings.menuCursor = 0
 27		model, _ := settings.updateMenu(tea.KeyPressMsg{Code: tea.KeyUp})
 28		settings = model.(*Settings)
 29		if settings.menuCursor != int(CategoryPlugins) {
 30			t.Fatalf("up from first menu item should wrap to last, got %d", settings.menuCursor)
 31		}
 32
 33		model, _ = settings.updateMenu(tea.KeyPressMsg{Code: tea.KeyDown})
 34		settings = model.(*Settings)
 35		if settings.menuCursor != 0 {
 36			t.Fatalf("down from last menu item should wrap to first, got %d", settings.menuCursor)
 37		}
 38	})
 39
 40	t.Run("general", func(t *testing.T) {
 41		settings.generalCursor = 0
 42		last := len(settings.buildGeneralOptions()) - 1
 43
 44		model, _ := settings.updateGeneral(tea.KeyPressMsg{Code: tea.KeyUp})
 45		settings = model.(*Settings)
 46		if settings.generalCursor != last {
 47			t.Fatalf("up from first general item should wrap to last, got %d", settings.generalCursor)
 48		}
 49
 50		model, _ = settings.updateGeneral(tea.KeyPressMsg{Code: tea.KeyDown})
 51		settings = model.(*Settings)
 52		if settings.generalCursor != 0 {
 53			t.Fatalf("down from last general item should wrap to first, got %d", settings.generalCursor)
 54		}
 55	})
 56
 57	t.Run("accounts", func(t *testing.T) {
 58		settings.accountsCursor = 0
 59		last := len(settings.cfg.Accounts)
 60
 61		model, _ := settings.updateAccounts(tea.KeyPressMsg{Code: tea.KeyUp})
 62		settings = model.(*Settings)
 63		if settings.accountsCursor != last {
 64			t.Fatalf("up from first account item should wrap to add account, got %d", settings.accountsCursor)
 65		}
 66
 67		model, _ = settings.updateAccounts(tea.KeyPressMsg{Code: tea.KeyDown})
 68		settings = model.(*Settings)
 69		if settings.accountsCursor != 0 {
 70			t.Fatalf("down from add account should wrap to first, got %d", settings.accountsCursor)
 71		}
 72	})
 73
 74	t.Run("mailing lists", func(t *testing.T) {
 75		settings.listsCursor = 0
 76		last := len(settings.cfg.MailingLists)
 77
 78		model, _ := settings.updateMailingLists(tea.KeyPressMsg{Code: tea.KeyUp})
 79		settings = model.(*Settings)
 80		if settings.listsCursor != last {
 81			t.Fatalf("up from first mailing list should wrap to add list, got %d", settings.listsCursor)
 82		}
 83
 84		model, _ = settings.updateMailingLists(tea.KeyPressMsg{Code: tea.KeyDown})
 85		settings = model.(*Settings)
 86		if settings.listsCursor != 0 {
 87			t.Fatalf("down from add list should wrap to first, got %d", settings.listsCursor)
 88		}
 89	})
 90
 91	t.Run("theme", func(t *testing.T) {
 92		themes := theme.AllThemes()
 93		if len(themes) < 2 {
 94			t.Skip("need at least two themes to test wrap-around")
 95		}
 96
 97		settings.themeCursor = 0
 98		model, _ := settings.updateTheme(tea.KeyPressMsg{Code: tea.KeyUp})
 99		settings = model.(*Settings)
100		if settings.themeCursor != len(themes)-1 {
101			t.Fatalf("up from first theme should wrap to last, got %d", settings.themeCursor)
102		}
103
104		model, _ = settings.updateTheme(tea.KeyPressMsg{Code: tea.KeyDown})
105		settings = model.(*Settings)
106		if settings.themeCursor != 0 {
107			t.Fatalf("down from last theme should wrap to first, got %d", settings.themeCursor)
108		}
109	})
110}
111
112func TestFilePickerNavigationWraps(t *testing.T) {
113	dir := t.TempDir()
114	if err := os.WriteFile(filepath.Join(dir, "a.txt"), []byte("a"), 0o600); err != nil {
115		t.Fatal(err)
116	}
117	if err := os.WriteFile(filepath.Join(dir, "b.txt"), []byte("b"), 0o600); err != nil {
118		t.Fatal(err)
119	}
120
121	picker := NewFilePicker(dir)
122	if len(picker.items) != 2 {
123		t.Fatalf("expected two picker items, got %d", len(picker.items))
124	}
125
126	model, _ := picker.Update(tea.KeyPressMsg{Code: tea.KeyUp})
127	picker = model.(*FilePicker)
128	if picker.cursor != len(picker.items)-1 {
129		t.Fatalf("up from first file should wrap to last, got %d", picker.cursor)
130	}
131
132	model, _ = picker.Update(tea.KeyPressMsg{Code: tea.KeyDown})
133	picker = model.(*FilePicker)
134	if picker.cursor != 0 {
135		t.Fatalf("down from last file should wrap to first, got %d", picker.cursor)
136	}
137}
138
139func TestFilePickerNavigationEmptyDirectoryDoesNotWrap(t *testing.T) {
140	picker := NewFilePicker(t.TempDir())
141	if len(picker.items) != 0 {
142		t.Fatalf("expected empty picker, got %d items", len(picker.items))
143	}
144
145	model, _ := picker.Update(tea.KeyPressMsg{Code: tea.KeyUp})
146	picker = model.(*FilePicker)
147	if picker.cursor != 0 {
148		t.Fatalf("empty picker cursor should remain zero after up, got %d", picker.cursor)
149	}
150
151	model, _ = picker.Update(tea.KeyPressMsg{Code: tea.KeyDown})
152	picker = model.(*FilePicker)
153	if picker.cursor != 0 {
154		t.Fatalf("empty picker cursor should remain zero after down, got %d", picker.cursor)
155	}
156}