Files
dingtalk-workspace-cli/internal/helpers/shell_quote_roundtrip_unix_test.go

77 lines
2.2 KiB
Go

//go:build !windows
package helpers
import (
"os/exec"
"testing"
)
// TestCrossPlatformCoverageShellQuoteArgRoundTrip 把引用后的串交给真 /bin/sh 求值,证明它被解析回
// **恰好一个、且内容完全相同**的参数。上面那条表驱动测试只能证明「我以为的形态」,这条证明
// 「shell 认的形态」——两者不是一回事,恢复命令是给用户复制到 shell 里跑的,后者才是契约。
//
// 它同时是注入的负向对照:一旦引用失效,$(id) / `id` 会真的执行、空格与 & 会拆参,argc 或
// 取回的值必然不等于原值,测试立刻红。用 build tag 排除 Windows(无 POSIX sh),跨平台形态
// 断言留在 shell_quote_test.go。
func TestCrossPlatformCoverageShellQuoteArgRoundTrip(t *testing.T) {
sh, err := exec.LookPath("sh")
if err != nil {
t.Skipf("POSIX sh unavailable: %v", err)
}
values := []string{
"ws-1",
"https://alidocs.dingtalk.com/i/nodes/x?spaceId=1&type=doc",
"sp 7",
"a;id",
"a&b",
"a|b",
"$(id)",
"`id`",
"$HOME",
"*.txt",
"a>b",
`a\b`,
`a"b`,
"a!b",
"{a,b}",
"(a)",
"~/x",
"a#b",
"it's",
"'",
"a'b'c",
"",
"报表",
"a\tb",
"a\nb",
"--not-a-flag",
}
for _, want := range values {
t.Run(want, func(t *testing.T) {
quoted := ShellQuoteArg(want)
// 1) 未被拆参也未被吞掉:位置参数个数必须恰好为 1。
// 引用失效时 "sp 7" 会变 2 个、"" 会变 0 个、$(id) 会变 id 的输出词数。
argc, err := exec.Command(sh, "-c", "set -- "+quoted+`; printf %s "$#"`).Output()
if err != nil {
t.Fatalf("argc probe failed for %q (quoted %s): %v", want, quoted, err)
}
if string(argc) != "1" {
t.Fatalf("argc = %s, want 1 — %q quoted as %s split or vanished", argc, want, quoted)
}
// 2) 内容逐字节相同:展开、命令替换、转义都不得改动值。
got, err := exec.Command(sh, "-c", "set -- "+quoted+`; printf %s "$1"`).Output()
if err != nil {
t.Fatalf("value probe failed for %q (quoted %s): %v", want, quoted, err)
}
if string(got) != want {
t.Fatalf("round-trip mismatch\n input: %q\n quoted: %s\n shell: %q", want, quoted, got)
}
})
}
}