Skip to content

Commit 735b5e8

Browse files
committed
Implement tests for shellwords parser functionality
Add tests for shellwords parser handling of unmatched and bare closing parentheses, command substitutions, and error cases.
1 parent e2951fc commit 735b5e8

1 file changed

Lines changed: 93 additions & 0 deletions

File tree

shellwords_security_test.go

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package shellwords
2+
3+
import (
4+
"strings"
5+
"testing"
6+
)
7+
8+
func TestUnmatchedClosingParen_NoPanic_ParseBacktickEnabled(t *testing.T) {
9+
p := NewParser()
10+
p.ParseBacktick = true
11+
12+
defer func() {
13+
if r := recover(); r != nil {
14+
t.Fatalf("unexpected panic: %v", r)
15+
}
16+
}()
17+
18+
out, err := p.Parse("))")
19+
if err != nil {
20+
t.Fatalf("unexpected error: %v", err)
21+
}
22+
23+
if len(out) != 1 || out[0] != "))" {
24+
t.Fatalf("unexpected output: %#v", out)
25+
}
26+
}
27+
28+
func TestBareClosingParen_DoesNotTriggerCommandExecution(t *testing.T) {
29+
p := NewParser()
30+
p.ParseBacktick = true
31+
32+
out, err := p.Parse("prefix)echo PWNED)")
33+
if err != nil {
34+
t.Fatalf("unexpected error: %v", err)
35+
}
36+
37+
got := strings.Join(out, " ")
38+
if strings.Contains(got, "PWNED") && got != "prefix)echo PWNED)" {
39+
t.Fatalf("unexpected command execution or substitution occurred: %q", got)
40+
}
41+
42+
want := []string{"prefix)echo", "PWNED)"}
43+
if len(out) != len(want) {
44+
t.Fatalf("unexpected token count: got %d, want %d, out=%#v", len(out), len(want), out)
45+
}
46+
for i := range want {
47+
if out[i] != want[i] {
48+
t.Fatalf("unexpected token at %d: got %q, want %q, out=%#v", i, out[i], want[i], out)
49+
}
50+
}
51+
}
52+
53+
func TestBareClosingParen_DefaultParsingLiteral(t *testing.T) {
54+
out, err := Parse(")a b)c d")
55+
if err != nil {
56+
t.Fatalf("unexpected error: %v", err)
57+
}
58+
59+
want := []string{")a", "b)c", "d"}
60+
if len(out) != len(want) {
61+
t.Fatalf("unexpected token count: got %d, want %d, out=%#v", len(out), len(want), out)
62+
}
63+
for i := range want {
64+
if out[i] != want[i] {
65+
t.Fatalf("unexpected token at %d: got %q, want %q, out=%#v", i, out[i], want[i], out)
66+
}
67+
}
68+
}
69+
70+
func TestValidDollarCommandSubstitutionStillWorks(t *testing.T) {
71+
p := NewParser()
72+
p.ParseBacktick = true
73+
74+
out, err := p.Parse("prefix $(printf hello) suffix")
75+
if err != nil {
76+
t.Fatalf("unexpected error: %v", err)
77+
}
78+
79+
got := strings.Join(out, " ")
80+
if !strings.Contains(got, "hello") {
81+
t.Fatalf("expected valid command substitution to work, got: %q", got)
82+
}
83+
}
84+
85+
func TestUnclosedDollarCommandSubstitutionReturnsError(t *testing.T) {
86+
p := NewParser()
87+
p.ParseBacktick = true
88+
89+
_, err := p.Parse("prefix $(echo hello")
90+
if err == nil {
91+
t.Fatal("expected error for unclosed command substitution, got nil")
92+
}
93+
}

0 commit comments

Comments
 (0)