106 lines
2.4 KiB
Go
106 lines
2.4 KiB
Go
package tools
|
|
|
|
import (
|
|
"reflect"
|
|
"testing"
|
|
)
|
|
|
|
func TestShellSplitPatterns(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
command string
|
|
patterns []string
|
|
always []string
|
|
ok bool // false = ожидаем nil (непарсится -> безопасный отказ)
|
|
}{
|
|
{
|
|
name: "single command",
|
|
command: "cat /etc/hosts",
|
|
patterns: []string{"cat /etc/hosts"},
|
|
always: []string{"cat *"},
|
|
ok: true,
|
|
},
|
|
{
|
|
name: "chain with &&",
|
|
command: "git status && git log",
|
|
patterns: []string{"git status", "git log"},
|
|
always: []string{"git status *", "git log *"},
|
|
ok: true,
|
|
},
|
|
{
|
|
name: "chain with semicolon hides destructive",
|
|
command: "cat /etc/hosts; rm -rf /",
|
|
patterns: []string{"cat /etc/hosts", "rm -rf /"},
|
|
always: []string{"cat *", "rm *"},
|
|
ok: true,
|
|
},
|
|
{
|
|
name: "pipe",
|
|
command: "ps aux | grep sshd",
|
|
patterns: []string{"ps aux", "grep sshd"},
|
|
always: []string{"ps aux *", "grep sshd *"},
|
|
ok: true,
|
|
},
|
|
{
|
|
name: "command substitution",
|
|
command: "echo $(rm -rf /tmp)",
|
|
patterns: []string{"echo $(rm -rf /tmp)", "rm -rf /tmp"},
|
|
always: []string{"echo *", "rm *"},
|
|
ok: true,
|
|
},
|
|
{
|
|
name: "sh -c hides destructive",
|
|
command: "sh -c 'rm -rf /'",
|
|
patterns: []string{"sh -c 'rm -rf /'", "rm -rf /"},
|
|
always: []string{"sh *", "rm *"},
|
|
ok: true,
|
|
},
|
|
{
|
|
name: "quoted semicolon not split",
|
|
command: "echo 'a;b'",
|
|
patterns: []string{"echo 'a;b'"},
|
|
always: []string{"echo *"},
|
|
ok: true,
|
|
},
|
|
{
|
|
name: "redirection",
|
|
command: "echo hi > /etc/foo",
|
|
patterns: []string{"echo hi > /etc/foo"},
|
|
always: []string{"echo *"},
|
|
ok: true,
|
|
},
|
|
{
|
|
name: "unbalanced quote -> nil",
|
|
command: "echo 'unterminated",
|
|
patterns: nil,
|
|
always: nil,
|
|
ok: false,
|
|
},
|
|
{
|
|
name: "empty",
|
|
command: "",
|
|
patterns: nil,
|
|
always: nil,
|
|
ok: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
p, a := shellSplitPatterns(tt.command)
|
|
if !tt.ok {
|
|
if p != nil || a != nil {
|
|
t.Fatalf("expected nil patterns/always, got %v / %v", p, a)
|
|
}
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(p, tt.patterns) {
|
|
t.Fatalf("patterns = %v, want %v", p, tt.patterns)
|
|
}
|
|
if !reflect.DeepEqual(a, tt.always) {
|
|
t.Fatalf("always = %v, want %v", a, tt.always)
|
|
}
|
|
})
|
|
}
|
|
}
|