1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
package terminal
import (
"testing"
"unicode/utf16"
)
// These run on every platform: they check the shapes Windows wants things in,
// not Windows itself. The API calls that consume them are compiled with
// GOOS=windows and have never been run by this project's authors — see
// README.md.
func TestWindowsShellIsComspecOrCmd(t *testing.T) {
if got := windowsShell(`C:\Windows\system32\cmd.exe`); got != `C:\Windows\system32\cmd.exe` {
t.Errorf("windowsShell(COMSPEC) = %q, want COMSPEC itself", got)
}
if got := windowsShell(""); got != "cmd.exe" {
t.Errorf("windowsShell(\"\") = %q, want the fallback cmd.exe", got)
}
}
func TestTheEnvironmentBlockIsNulSeparatedAndDoubleNulEnded(t *testing.T) {
block := environmentBlock([]string{"A=1", "TERM=xterm-256color"})
want := append(utf16.Encode([]rune("A=1")), 0)
want = append(want, utf16.Encode([]rune("TERM=xterm-256color"))...)
want = append(want, 0, 0)
if len(block) != len(want) {
t.Fatalf("block has %d code units, want %d", len(block), len(want))
}
for i := range want {
if block[i] != want[i] {
t.Fatalf("block differs at %d: %v, want %v", i, block, want)
}
}
}
func TestTheEnvironmentBlockKeepsNonASCII(t *testing.T) {
// UTF-16, not bytes: a variable holding an accent must survive.
block := environmentBlock([]string{"NAME=élan"})
if got := string(utf16.Decode(block[:len(block)-2])); got != "NAME=élan" {
t.Errorf("the block decodes to %q, want NAME=élan", got)
}
}
func TestAnEmptyEnvironmentIsTwoNuls(t *testing.T) {
// A single NUL would be a block whose first entry is empty and which then
// runs off the end; nil would mean "inherit", which the caller never
// wants because TERM is set. Two NULs is the documented empty block.
if got := environmentBlock(nil); len(got) != 2 || got[0] != 0 || got[1] != 0 {
t.Errorf("environmentBlock(nil) = %v, want two NULs", got)
}
}
func TestCmdExeGetsItsCommandVerbatimInsideOnePairOfQuotes(t *testing.T) {
// cmd.exe /S /C strips the first and last quote and parses the rest by
// its own rules, so a quote inside the command must reach it unescaped.
got := windowsCommandLine(`C:\Windows\system32\cmd.exe`, []string{"/S", "/C", `echo "hello world" && node --test`})
want := `"C:\Windows\system32\cmd.exe" /S /C "echo "hello world" && node --test"`
if got != want {
t.Errorf("windowsCommandLine() = %s, want %s", got, want)
}
}
func TestCmdExeIsRecognisedWhateverItsCaseOrPath(t *testing.T) {
for _, program := range []string{"cmd.exe", "CMD.EXE", `C:\WINDOWS\System32\Cmd.exe`, "cmd"} {
if !isCmdExe(program) {
t.Errorf("isCmdExe(%q) = false, want true", program)
}
}
for _, program := range []string{"pwsh.exe", `C:\Program Files\PowerShell\7\pwsh.exe`, "bash"} {
if isCmdExe(program) {
t.Errorf("isCmdExe(%q) = true, want false", program)
}
}
}
func TestAnInteractiveCmdExeHasNoSwitchesToSpecialCase(t *testing.T) {
// No arguments: the ordinary composition, which is just the program.
if got := windowsCommandLine("cmd.exe", nil); got != "cmd.exe" {
t.Errorf("windowsCommandLine(cmd.exe) = %q, want cmd.exe", got)
}
}
func TestOtherProgramsGetCRuntimeQuoting(t *testing.T) {
// The rule syscall.EscapeArg follows: quotes around an argument with a
// space, \" for a quote, backslashes doubled only before a quote.
tests := []struct {
program string
args []string
want string
}{
{"pwsh.exe", []string{"-NoLogo"}, `pwsh.exe -NoLogo`},
{`C:\Program Files\PowerShell\7\pwsh.exe`, []string{"-c", "echo hi"}, `"C:\Program Files\PowerShell\7\pwsh.exe" -c "echo hi"`},
{"node", []string{"-e", `console.log("x")`}, `node -e "console.log(\"x\")"`},
{"node", []string{`C:\path with space\`}, `node "C:\path with space\\"`},
{"node", []string{`a\"b`}, `node "a\\\"b"`},
{"node", []string{""}, `node ""`},
}
for _, test := range tests {
if got := windowsCommandLine(test.program, test.args); got != test.want {
t.Errorf("windowsCommandLine(%q, %q) = %s, want %s", test.program, test.args, got, test.want)
}
}
}
func TestProgramNameDropsWindowsAndUnixPaths(t *testing.T) {
for program, want := range map[string]string{
`C:\Windows\system32\cmd.exe`: "cmd.exe",
"/bin/sh": "sh",
"pwsh.exe": "pwsh.exe",
} {
if got := programName(program); got != want {
t.Errorf("programName(%q) = %q, want %q", program, got, want)
}
}
}
|