blob: 8b8f330e9910a515bb832e529b5b4dcce2c27dcd [file] [log] [blame]
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package syscall_test
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"syscall"
"testing"
"time"
)
func TestEscapeArg(t *testing.T) {
var tests = []struct {
input, output string
}{
{``, `""`},
{`a`, `a`},
{` `, `" "`},
{`\`, `\`},
{`"`, `\"`},
{`\"`, `\\\"`},
{`\\"`, `\\\\\"`},
{`\\ `, `"\\ "`},
{` \\`, `" \\\\"`},
{`a `, `"a "`},
{`C:\`, `C:\`},
{`C:\Program Files (x32)\Common\`, `"C:\Program Files (x32)\Common\\"`},
{`C:\Users\Игорь\`, `C:\Users\Игорь\`},
{`Андрей\file`, `Андрей\file`},
{`C:\Windows\temp`, `C:\Windows\temp`},
{`c:\temp\newfile`, `c:\temp\newfile`},
{`\\?\C:\Windows`, `\\?\C:\Windows`},
{`\\?\`, `\\?\`},
{`\\.\C:\Windows\`, `\\.\C:\Windows\`},
{`\\server\share\file`, `\\server\share\file`},
{`\\newserver\tempshare\really.txt`, `\\newserver\tempshare\really.txt`},
}
for _, test := range tests {
if got := syscall.EscapeArg(test.input); got != test.output {
t.Errorf("EscapeArg(%#q) = %#q, want %#q", test.input, got, test.output)
}
}
}
func TestChangingProcessParent(t *testing.T) {
if os.Getenv("GO_WANT_HELPER_PROCESS") == "parent" {
// in parent process
// Parent does nothing. It is just used as a parent of a child process.
time.Sleep(time.Minute)
os.Exit(0)
}
if os.Getenv("GO_WANT_HELPER_PROCESS") == "child" {
// in child process
dumpPath := os.Getenv("GO_WANT_HELPER_PROCESS_FILE")
if dumpPath == "" {
fmt.Fprintf(os.Stderr, "Dump file path cannot be blank.")
os.Exit(1)
}
err := os.WriteFile(dumpPath, []byte(fmt.Sprintf("%d", os.Getppid())), 0644)
if err != nil {
fmt.Fprintf(os.Stderr, "Error writing dump file: %v", err)
os.Exit(2)
}
os.Exit(0)
}
// run parent process
parent := exec.Command(os.Args[0], "-test.run=TestChangingProcessParent")
parent.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=parent")
err := parent.Start()
if err != nil {
t.Fatal(err)
}
defer func() {
parent.Process.Kill()
parent.Wait()
}()
// run child process
const _PROCESS_CREATE_PROCESS = 0x0080
const _PROCESS_DUP_HANDLE = 0x0040
childDumpPath := filepath.Join(t.TempDir(), "ppid.txt")
ph, err := syscall.OpenProcess(_PROCESS_CREATE_PROCESS|_PROCESS_DUP_HANDLE|syscall.PROCESS_QUERY_INFORMATION,
false, uint32(parent.Process.Pid))
if err != nil {
t.Fatal(err)
}
defer syscall.CloseHandle(ph)
child := exec.Command(os.Args[0], "-test.run=TestChangingProcessParent")
child.Env = append(os.Environ(),
"GO_WANT_HELPER_PROCESS=child",
"GO_WANT_HELPER_PROCESS_FILE="+childDumpPath)
child.SysProcAttr = &syscall.SysProcAttr{ParentProcess: ph}
childOutput, err := child.CombinedOutput()
if err != nil {
t.Errorf("child failed: %v: %v", err, string(childOutput))
}
childOutput, err = os.ReadFile(childDumpPath)
if err != nil {
t.Fatalf("reading child output failed: %v", err)
}
if got, want := string(childOutput), fmt.Sprintf("%d", parent.Process.Pid); got != want {
t.Fatalf("child output: want %q, got %q", want, got)
}
}