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}