Source file
src/syscall/exec_windows_test.go
1
2
3
4
5 package syscall_test
6
7 import (
8 "fmt"
9 "internal/testenv"
10 "os"
11 "os/exec"
12 "path/filepath"
13 "slices"
14 "syscall"
15 "testing"
16 "time"
17 )
18
19 func TestEscapeArg(t *testing.T) {
20 var tests = []struct {
21 input, output string
22 }{
23 {``, `""`},
24 {`a`, `a`},
25 {` `, `" "`},
26 {`\`, `\`},
27 {`"`, `\"`},
28 {`\"`, `\\\"`},
29 {`\\"`, `\\\\\"`},
30 {`\\ `, `"\\ "`},
31 {` \\`, `" \\\\"`},
32 {`a `, `"a "`},
33 {`C:\`, `C:\`},
34 {`C:\Program Files (x32)\Common\`, `"C:\Program Files (x32)\Common\\"`},
35 {`C:\Users\Игорь\`, `C:\Users\Игорь\`},
36 {`Андрей\file`, `Андрей\file`},
37 {`C:\Windows\temp`, `C:\Windows\temp`},
38 {`c:\temp\newfile`, `c:\temp\newfile`},
39 {`\\?\C:\Windows`, `\\?\C:\Windows`},
40 {`\\?\`, `\\?\`},
41 {`\\.\C:\Windows\`, `\\.\C:\Windows\`},
42 {`\\server\share\file`, `\\server\share\file`},
43 {`\\newserver\tempshare\really.txt`, `\\newserver\tempshare\really.txt`},
44 }
45 for _, test := range tests {
46 if got := syscall.EscapeArg(test.input); got != test.output {
47 t.Errorf("EscapeArg(%#q) = %#q, want %#q", test.input, got, test.output)
48 }
49 }
50 }
51
52 func TestEnvBlockSorted(t *testing.T) {
53 tests := []struct {
54 env []string
55 want []string
56 }{
57 {},
58 {
59 env: []string{"A=1"},
60 want: []string{"A=1"},
61 },
62 {
63 env: []string{"A=1", "B=2", "C=3"},
64 want: []string{"A=1", "B=2", "C=3"},
65 },
66 {
67 env: []string{"C=3", "B=2", "A=1"},
68 want: []string{"A=1", "B=2", "C=3"},
69 },
70 {
71 env: []string{"c=3", "B=2", "a=1"},
72 want: []string{"a=1", "B=2", "c=3"},
73 },
74 }
75 for _, tt := range tests {
76 got := syscall.EnvSorted(tt.env)
77 if !slices.Equal(got, tt.want) {
78 t.Errorf("EnvSorted(%q) = %q, want %q", tt.env, got, tt.want)
79 }
80 }
81 }
82
83 func TestChangingProcessParent(t *testing.T) {
84 if os.Getenv("GO_WANT_HELPER_PROCESS") == "parent" {
85
86
87
88 time.Sleep(time.Minute)
89 os.Exit(0)
90 }
91
92 if os.Getenv("GO_WANT_HELPER_PROCESS") == "child" {
93
94 dumpPath := os.Getenv("GO_WANT_HELPER_PROCESS_FILE")
95 if dumpPath == "" {
96 fmt.Fprintf(os.Stderr, "Dump file path cannot be blank.")
97 os.Exit(1)
98 }
99 err := os.WriteFile(dumpPath, []byte(fmt.Sprintf("%d", os.Getppid())), 0644)
100 if err != nil {
101 fmt.Fprintf(os.Stderr, "Error writing dump file: %v", err)
102 os.Exit(2)
103 }
104 os.Exit(0)
105 }
106
107
108
109 parent := exec.Command(testenv.Executable(t), "-test.run=^TestChangingProcessParent$")
110 parent.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=parent")
111 err := parent.Start()
112 if err != nil {
113 t.Fatal(err)
114 }
115 defer func() {
116 parent.Process.Kill()
117 parent.Wait()
118 }()
119
120
121
122 const _PROCESS_CREATE_PROCESS = 0x0080
123 const _PROCESS_DUP_HANDLE = 0x0040
124 childDumpPath := filepath.Join(t.TempDir(), "ppid.txt")
125 ph, err := syscall.OpenProcess(_PROCESS_CREATE_PROCESS|_PROCESS_DUP_HANDLE|syscall.PROCESS_QUERY_INFORMATION,
126 false, uint32(parent.Process.Pid))
127 if err != nil {
128 t.Fatal(err)
129 }
130 defer syscall.CloseHandle(ph)
131
132 child := exec.Command(testenv.Executable(t), "-test.run=^TestChangingProcessParent$")
133 child.Env = append(os.Environ(),
134 "GO_WANT_HELPER_PROCESS=child",
135 "GO_WANT_HELPER_PROCESS_FILE="+childDumpPath)
136 child.SysProcAttr = &syscall.SysProcAttr{ParentProcess: ph}
137 childOutput, err := child.CombinedOutput()
138 if err != nil {
139 t.Errorf("child failed: %v: %v", err, string(childOutput))
140 }
141 childOutput, err = os.ReadFile(childDumpPath)
142 if err != nil {
143 t.Fatalf("reading child output failed: %v", err)
144 }
145 if got, want := string(childOutput), fmt.Sprintf("%d", parent.Process.Pid); got != want {
146 t.Fatalf("child output: want %q, got %q", want, got)
147 }
148 }
149
View as plain text