startup_pre_test.go RawHistoryFolder
1package modes
2
3import (
4 "context"
5 "runtime"
6 "strings"
7 "testing"
8 "time"
9
10 "github.com/bnema/zut/packages/core"
11)
12
13func applyStartupPreResultForTest(t *testing.T, i *Interactive) {
14 t.Helper()
15 select {
16 case result := <-i.startupPreDone:
17 i.applyStartupPreResult(result)
18 default:
19 t.Fatal("startup pre result was not queued")
20 }
21}
22
23func TestCompleteStartupPrePrefillsEditor(t *testing.T) {
24 i := NewInteractive(InteractiveConfig{})
25 i.awaitingStartupPre = true
26 i.deferredInitialInput = "Bom dia!"
27 i.autoSubmitDeferred = false
28 i.completeStartupPre()
29 applyStartupPreResultForTest(t, i)
30 if got := i.ed.Value(); got != "Bom dia!" {
31 t.Fatalf("editor = %q, want Bom dia!", got)
32 }
33 i.mu.Lock()
34 awaiting := i.awaitingStartupPre
35 i.mu.Unlock()
36 if awaiting {
37 t.Fatal("awaitingStartupPre still set after completeStartupPre")
38 }
39}
40
41func TestStartupPrePrefillPreservesTypedInput(t *testing.T) {
42 i := NewInteractive(InteractiveConfig{})
43 i.ed.SetValue("typed while reloading")
44 i.applyStartupPreResult(startupPreResult{deferred: "default prompt"})
45 if got := i.ed.Value(); got != "typed while reloading" {
46 t.Fatalf("editor = %q, want typed input to be preserved", got)
47 }
48}
49
50func TestCompleteStartupPreCallsOnDone(t *testing.T) {
51 called := false
52 i := NewInteractive(InteractiveConfig{
53 OnStartupPreDone: func() { called = true },
54 })
55 i.awaitingStartupPre = true
56 i.completeStartupPre()
57 if !called {
58 t.Fatal("OnStartupPreDone was not called")
59 }
60}
61
62func TestStartupPreShellWithoutAgentThenPrefill(t *testing.T) {
63 i := NewInteractive(InteractiveConfig{CWD: t.TempDir()})
64 i.runCtx = context.Background()
65 i.awaitingStartupPre = true
66 i.deferredInitialInput = "after-pre"
67 i.autoSubmitDeferred = false
68
69 cmd := "printf zut-pre"
70 if runtime.GOOS == "windows" {
71 cmd = "echo zut-pre"
72 }
73 i.startShellEscape(context.Background(), cmd)
74
75 deadline := time.Now().Add(5 * time.Second)
76 for time.Now().Before(deadline) {
77 select {
78 case result := <-i.startupPreDone:
79 i.applyStartupPreResult(result)
80 default:
81 }
82 i.mu.Lock()
83 running := i.shellRunning
84 awaiting := i.awaitingStartupPre
85 i.mu.Unlock()
86 if !running && !awaiting {
87 if got := i.ed.Value(); got != "after-pre" {
88 t.Fatalf("editor = %q, want after-pre", got)
89 }
90 return
91 }
92 time.Sleep(10 * time.Millisecond)
93 }
94 t.Fatal("startup pre did not complete and prefill the editor")
95}
96
97func TestStartupPreShellThenAutoSubmitShell(t *testing.T) {
98 agent := core.NewAgent(nil, "", "", nil)
99 i := NewInteractive(InteractiveConfig{Agent: agent, CWD: t.TempDir()})
100 i.runCtx = context.Background()
101 i.awaitingStartupPre = true
102 i.deferredInitialInput = "!printf zut-default"
103 if runtime.GOOS == "windows" {
104 i.deferredInitialInput = "!echo zut-default"
105 }
106 i.autoSubmitDeferred = true
107
108 cmd := "printf zut-pre"
109 if runtime.GOOS == "windows" {
110 cmd = "echo zut-pre"
111 }
112 i.startShellEscape(context.Background(), cmd)
113
114 deadline := time.Now().Add(5 * time.Second)
115 for time.Now().Before(deadline) {
116 select {
117 case result := <-i.startupPreDone:
118 i.applyStartupPreResult(result)
119 default:
120 }
121 messages := agent.Messages()
122 i.mu.Lock()
123 running := i.shellRunning || i.busy
124 awaiting := i.awaitingStartupPre
125 i.mu.Unlock()
126 if len(messages) >= 2 && !running && !awaiting {
127 joined := userMessageText(messages[0]) + "\n" + userMessageText(messages[1])
128 if !strings.Contains(joined, "zut-pre") || !strings.Contains(joined, "zut-default") {
129 t.Fatalf("context = %q, want both pre and default shell output", joined)
130 }
131 return
132 }
133 time.Sleep(10 * time.Millisecond)
134 }
135 t.Fatal("startup pre did not auto-submit the deferred prompt")
136}