confirm_test.go

  1package screens
  2
  3import (
  4	"strings"
  5	"testing"
  6
  7	tea "charm.land/bubbletea/v2"
  8
  9	"git.secluded.site/keld/internal/ui"
 10)
 11
 12func TestConfirmTitle(t *testing.T) {
 13	t.Parallel()
 14
 15	c := NewConfirm(func() string { return "command: restic backup\n" }, false)
 16	if got := c.Title(); got != "Confirm execution" {
 17		t.Errorf("Title() = %q, want %q", got, "Confirm execution")
 18	}
 19}
 20
 21func TestConfirmSelectionEmpty(t *testing.T) {
 22	t.Parallel()
 23
 24	c := NewConfirm(func() string { return "command: restic backup\n" }, false)
 25	if got := c.Selection(); got != "" {
 26		t.Errorf("Selection() before interaction = %q, want empty", got)
 27	}
 28}
 29
 30func TestConfirmKeyBindings(t *testing.T) {
 31	t.Parallel()
 32
 33	c := NewConfirm(func() string { return "command: restic backup\n" }, false)
 34	bindings := c.KeyBindings()
 35
 36	if len(bindings) == 0 {
 37		t.Fatal("KeyBindings() returned no bindings")
 38	}
 39}
 40
 41func TestConfirmInitCallsPreviewFunc(t *testing.T) {
 42	t.Parallel()
 43
 44	called := false
 45	c := NewConfirm(func() string {
 46		called = true
 47		return "command: restic backup\n"
 48	}, false)
 49
 50	cmd := c.Init()
 51	// The preview func is called asynchronously via a tea.Cmd.
 52	// Execute the returned cmd to get the message.
 53	if cmd != nil {
 54		msg := cmd()
 55		c.Update(msg)
 56	}
 57
 58	if !called {
 59		t.Error("Init() did not call the preview function")
 60	}
 61}
 62
 63func TestConfirmViewShowsPreviewText(t *testing.T) {
 64	t.Parallel()
 65
 66	preview := "environ:\n  RESTIC_REPOSITORY=/repo\ncommand: \"restic\" \"backup\" \"/src\"\n"
 67	c := NewConfirm(func() string { return preview }, false)
 68
 69	cmd := c.Init()
 70	if cmd != nil {
 71		msg := cmd()
 72		c.Update(msg)
 73	}
 74
 75	view := c.View()
 76	if !strings.Contains(view, "RESTIC_REPOSITORY") {
 77		t.Errorf("View() missing environ; got:\n%s", view)
 78	}
 79	if !strings.Contains(view, "restic") {
 80		t.Errorf("View() missing command; got:\n%s", view)
 81	}
 82}
 83
 84func TestConfirmEscReturnsBack(t *testing.T) {
 85	t.Parallel()
 86
 87	c := NewConfirm(func() string { return "command: restic backup\n" }, false)
 88	cmd := c.Init()
 89	if cmd != nil {
 90		msg := cmd()
 91		c.Update(msg)
 92	}
 93
 94	_, cmd = c.Update(tea.KeyPressMsg{Code: tea.KeyEscape})
 95
 96	if cmd == nil {
 97		t.Fatal("expected BackCmd on Esc")
 98	}
 99	msg := cmd()
100	if _, ok := msg.(ui.BackMsg); !ok {
101		t.Errorf("cmd produced %T, want ui.BackMsg", msg)
102	}
103}
104
105func TestConfirmEnterReturnsDone(t *testing.T) {
106	t.Parallel()
107
108	c := NewConfirm(func() string { return "command: restic backup\n" }, false)
109	cmd := c.Init()
110	if cmd != nil {
111		msg := cmd()
112		c.Update(msg)
113	}
114
115	_, cmd = c.Update(tea.KeyPressMsg{Code: tea.KeyEnter})
116
117	if cmd == nil {
118		t.Fatal("expected DoneCmd on Enter")
119	}
120	msg := cmd()
121	if _, ok := msg.(ui.DoneMsg); !ok {
122		t.Errorf("cmd produced %T, want ui.DoneMsg", msg)
123	}
124}
125
126func TestConfirmSelectionAfterEnter(t *testing.T) {
127	t.Parallel()
128
129	c := NewConfirm(func() string { return "command: restic backup\n" }, false)
130	cmd := c.Init()
131	if cmd != nil {
132		msg := cmd()
133		c.Update(msg)
134	}
135
136	c.Update(tea.KeyPressMsg{Code: tea.KeyEnter})
137
138	if got := c.Selection(); got != "confirmed" {
139		t.Errorf("Selection() after enter = %q, want %q", got, "confirmed")
140	}
141}
142
143func TestConfirmShowCommandAutoCompletes(t *testing.T) {
144	t.Parallel()
145
146	// When --show-command is active, Init should return DoneCmd
147	// immediately so the session completes without user interaction.
148	c := NewConfirm(func() string { return "command: restic backup\n" }, true)
149	cmd := c.Init()
150
151	if cmd == nil {
152		t.Fatal("expected DoneCmd from Init when showCommand is true")
153	}
154	msg := cmd()
155	if _, ok := msg.(ui.DoneMsg); !ok {
156		t.Errorf("Init() with showCommand produced %T, want ui.DoneMsg", msg)
157	}
158}
159
160func TestConfirmShowCommandSkipsPreview(t *testing.T) {
161	t.Parallel()
162
163	called := false
164	c := NewConfirm(func() string {
165		called = true
166		return "command: restic backup\n"
167	}, true)
168
169	c.Init()
170
171	if called {
172		t.Error("preview function should not be called when showCommand is true")
173	}
174}
175
176func TestConfirmViewEmptyBeforeInit(t *testing.T) {
177	t.Parallel()
178
179	c := NewConfirm(func() string { return "command: restic backup\n" }, false)
180	if got := c.View(); got != "" {
181		t.Errorf("View() before Init = %q, want empty", got)
182	}
183}
184
185func TestConfirmPartialShowsNote(t *testing.T) {
186	t.Parallel()
187
188	c := NewConfirm(func() string { return "command: restic backup\n" }, false)
189	c.SetPartial(true)
190
191	cmd := c.Init()
192	if cmd != nil {
193		msg := cmd()
194		c.Update(msg)
195	}
196
197	view := c.View()
198	if !strings.Contains(view, "may be incomplete") {
199		t.Errorf("partial View() missing incomplete note; got:\n%s", view)
200	}
201	if !strings.Contains(view, "--show-command") {
202		t.Errorf("partial View() missing --show-command hint; got:\n%s", view)
203	}
204}
205
206func TestConfirmNonPartialOmitsNote(t *testing.T) {
207	t.Parallel()
208
209	c := NewConfirm(func() string { return "command: restic backup\n" }, false)
210
211	cmd := c.Init()
212	if cmd != nil {
213		msg := cmd()
214		c.Update(msg)
215	}
216
217	view := c.View()
218	if strings.Contains(view, "may be incomplete") {
219		t.Errorf("non-partial View() should not contain incomplete note; got:\n%s", view)
220	}
221}
222
223func TestConfirmReinitAfterBack(t *testing.T) {
224	t.Parallel()
225
226	c := NewConfirm(func() string { return "command: restic backup\n" }, false)
227	cmd := c.Init()
228	if cmd != nil {
229		msg := cmd()
230		c.Update(msg)
231	}
232
233	// Confirm.
234	c.Update(tea.KeyPressMsg{Code: tea.KeyEnter})
235
236	// Re-init (simulates back navigation and return).
237	cmd = c.Init()
238	if cmd != nil {
239		msg := cmd()
240		c.Update(msg)
241	}
242
243	// Should be functional again — selection should be cleared.
244	if got := c.Selection(); got != "" {
245		t.Errorf("Selection() after re-init = %q, want empty", got)
246	}
247
248	// Should still respond to Enter.
249	_, cmd = c.Update(tea.KeyPressMsg{Code: tea.KeyEnter})
250	if cmd == nil {
251		t.Fatal("expected DoneCmd after re-init and Enter")
252	}
253	msg := cmd()
254	if _, ok := msg.(ui.DoneMsg); !ok {
255		t.Errorf("after re-init, cmd produced %T, want ui.DoneMsg", msg)
256	}
257}