Skip to content

Commit b564fd7

Browse files
MattieTKclaude
andcommitted
test: add AwaitPrompt parser and shell prompt marker tests
Cover AwaitPrompt parsing with and without @timeout variants, and verify that all 9 supported shells embed the OSC 7777 prompt marker. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 20fb450 commit b564fd7

2 files changed

Lines changed: 129 additions & 1 deletion

File tree

parser/parser_test.go

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ Sleep 100ms
3333
Sleep 3
3434
Wait
3535
Wait+Screen
36-
Wait@100ms /foobar/`
36+
Wait@100ms /foobar/
37+
AwaitPrompt
38+
AwaitPrompt@30s`
3739

3840
expected := []Command{
3941
{Type: token.SET, Options: "TypingSpeed", Args: "100ms"},
@@ -59,6 +61,8 @@ Wait@100ms /foobar/`
5961
{Type: token.WAIT, Args: "Line"},
6062
{Type: token.WAIT, Args: "Screen"},
6163
{Type: token.WAIT, Options: "100ms", Args: "Line foobar"},
64+
{Type: token.AWAIT_PROMPT, Options: "", Args: ""},
65+
{Type: token.AWAIT_PROMPT, Options: "30s", Args: ""},
6266
}
6367

6468
l := lexer.New(input)
@@ -291,6 +295,66 @@ func TestParseCtrl(t *testing.T) {
291295
}
292296
}
293297

298+
func TestParseAwaitPrompt(t *testing.T) {
299+
t.Run("bare AwaitPrompt", func(t *testing.T) {
300+
l := lexer.New("AwaitPrompt")
301+
p := New(l)
302+
cmds := p.Parse()
303+
304+
if len(cmds) != 1 {
305+
t.Fatalf("Expected 1 command, got %d", len(cmds))
306+
}
307+
if cmds[0].Type != token.AWAIT_PROMPT {
308+
t.Errorf("Expected AWAIT_PROMPT, got %s", cmds[0].Type)
309+
}
310+
if cmds[0].Options != "" {
311+
t.Errorf("Expected empty options, got %s", cmds[0].Options)
312+
}
313+
})
314+
315+
t.Run("AwaitPrompt with timeout", func(t *testing.T) {
316+
l := lexer.New("AwaitPrompt@30s")
317+
p := New(l)
318+
cmds := p.Parse()
319+
320+
if len(cmds) != 1 {
321+
t.Fatalf("Expected 1 command, got %d", len(cmds))
322+
}
323+
if cmds[0].Type != token.AWAIT_PROMPT {
324+
t.Errorf("Expected AWAIT_PROMPT, got %s", cmds[0].Type)
325+
}
326+
if cmds[0].Options != "30s" {
327+
t.Errorf("Expected options '30s', got %s", cmds[0].Options)
328+
}
329+
})
330+
331+
t.Run("AwaitPrompt with millisecond timeout", func(t *testing.T) {
332+
l := lexer.New("AwaitPrompt@500ms")
333+
p := New(l)
334+
cmds := p.Parse()
335+
336+
if len(cmds) != 1 {
337+
t.Fatalf("Expected 1 command, got %d", len(cmds))
338+
}
339+
if cmds[0].Options != "500ms" {
340+
t.Errorf("Expected options '500ms', got %s", cmds[0].Options)
341+
}
342+
})
343+
344+
t.Run("AwaitPrompt with minute timeout", func(t *testing.T) {
345+
l := lexer.New("AwaitPrompt@2m")
346+
p := New(l)
347+
cmds := p.Parse()
348+
349+
if len(cmds) != 1 {
350+
t.Fatalf("Expected 1 command, got %d", len(cmds))
351+
}
352+
if cmds[0].Options != "2m" {
353+
t.Errorf("Expected options '2m', got %s", cmds[0].Options)
354+
}
355+
})
356+
}
357+
294358
type parseSourceTest struct {
295359
tape string
296360
srcTape string

shell_test.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package main
2+
3+
import (
4+
"strings"
5+
"testing"
6+
)
7+
8+
func TestHexToRGB(t *testing.T) {
9+
tests := []struct {
10+
hex string
11+
r, g, b int
12+
}{
13+
{"#5B56E0", 91, 86, 224},
14+
{"5B56E0", 91, 86, 224},
15+
{"#F6821F", 246, 130, 31},
16+
{"#000000", 0, 0, 0},
17+
{"#FFFFFF", 255, 255, 255},
18+
{"", 0, 0, 0},
19+
{"#FFF", 0, 0, 0}, // invalid length
20+
}
21+
22+
for _, tc := range tests {
23+
r, g, b := hexToRGB(tc.hex)
24+
if r != tc.r || g != tc.g || b != tc.b {
25+
t.Errorf("hexToRGB(%q) = (%d,%d,%d), want (%d,%d,%d)",
26+
tc.hex, r, g, b, tc.r, tc.g, tc.b)
27+
}
28+
}
29+
}
30+
31+
func TestShellConfigPromptMarker(t *testing.T) {
32+
// Every shell configuration should embed the OSC 7777 prompt marker
33+
// so that AwaitPrompt can detect when a command has finished.
34+
//
35+
// The marker format varies by shell:
36+
// - Most shells: \e]7777;\a (ESC ] 7777 ; BEL)
37+
// - cmd.exe: $E]7777;$E\ (using ST terminator instead of BEL)
38+
shellNames := []string{
39+
bash,
40+
zsh,
41+
fish,
42+
powershell,
43+
pwsh,
44+
cmdexe,
45+
nushell,
46+
osh,
47+
xonsh,
48+
}
49+
50+
color := "#5B56E0"
51+
52+
for _, name := range shellNames {
53+
t.Run(name, func(t *testing.T) {
54+
env, command := ShellConfig(name, color)
55+
56+
// Combine env and command into a single string to search
57+
combined := strings.Join(env, " ") + " " + strings.Join(command, " ")
58+
59+
if !strings.Contains(combined, "7777") {
60+
t.Errorf("ShellConfig(%q) does not contain OSC 7777 marker.\nenv: %v\ncommand: %v", name, env, command)
61+
}
62+
})
63+
}
64+
}

0 commit comments

Comments
 (0)