Skip to content

Commit

Permalink
Avoid treating \ as escape char on Windows
Browse files Browse the repository at this point in the history
Copy from mattn#39.
  • Loading branch information
y-yagi committed Aug 17, 2020
1 parent 28e4fdf commit 661cffe
Show file tree
Hide file tree
Showing 6 changed files with 180 additions and 59 deletions.
2 changes: 1 addition & 1 deletion shellwords.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ loop:
continue
}

if r == '\\' {
if isEscapeRune(r) {
if singleQuoted {
buf += string(r)
} else {
Expand Down
81 changes: 81 additions & 0 deletions shellwords_posix_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// +build !windows

package shellwords

import (
"fmt"
"os"
"path"
"reflect"
"testing"
)

func TestEscaping(t *testing.T) {
var testcases = []struct {
line string
expected []string
}{
{"foo bar\\ ", []string{`foo`, `bar `}},
{"foo 'bar\\ '", []string{`foo`, `bar\ `}},
{`var "--bar=\"baz'"`, []string{`var`, `--bar="baz'`}},
{`var "--bar=\'baz\'"`, []string{`var`, `--bar='baz'`}},
}

for i, testcase := range testcases {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
args, err := Parse(testcase.line)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(args, testcase.expected) {
t.Fatalf("Expected %#v for %q, but %#v:", testcase.expected, testcase.line, args)
}
})
}
}

func TestShellRun(t *testing.T) {
dir, err := os.Getwd()
if err != nil {
t.Fatal(err)
}

pwd, err := shellRun("pwd", "")
if err != nil {
t.Fatal(err)
}

pwd2, err := shellRun("pwd", path.Join(dir, "/_example"))
if err != nil {
t.Fatal(err)
}

if pwd == pwd2 {
t.Fatal("`pwd` should be changed")
}
}

func TestShellRunNoEnv(t *testing.T) {
old := os.Getenv("SHELL")
defer os.Setenv("SHELL", old)
os.Unsetenv("SHELL")

dir, err := os.Getwd()
if err != nil {
t.Fatal(err)
}

pwd, err := shellRun("pwd", "")
if err != nil {
t.Fatal(err)
}

pwd2, err := shellRun("pwd", path.Join(dir, "/_example"))
if err != nil {
t.Fatal(err)
}

if pwd == pwd2 {
t.Fatal("`pwd` should be changed")
}
}
69 changes: 11 additions & 58 deletions shellwords_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package shellwords

import (
"fmt"
"go/build"
"os"
"path"
"reflect"
"testing"
)
Expand All @@ -20,8 +20,6 @@ var testcases = []struct {
{`var "--bar=baz"`, []string{`var`, `--bar=baz`}},
{`var "--bar='baz'"`, []string{`var`, `--bar='baz'`}},
{"var --bar=`baz`", []string{`var`, "--bar=`baz`"}},
{`var "--bar=\"baz'"`, []string{`var`, `--bar="baz'`}},
{`var "--bar=\'baz\'"`, []string{`var`, `--bar='baz'`}},
{`var --bar='\'`, []string{`var`, `--bar=\`}},
{`var "--bar baz"`, []string{`var`, `--bar baz`}},
{`var --"bar baz"`, []string{`var`, `--bar baz`}},
Expand All @@ -32,19 +30,20 @@ var testcases = []struct {
{`a 'b'`, []string{`a`, `b`}},
{`a ' b '`, []string{`a`, ` b `}},
{`a ' '`, []string{`a`, ` `}},
{"foo bar\\ ", []string{`foo`, `bar `}},
{`foo "" bar ''`, []string{`foo`, ``, `bar`, ``}},
}

func TestSimple(t *testing.T) {
for _, testcase := range testcases {
args, err := Parse(testcase.line)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(args, testcase.expected) {
t.Fatalf("Expected %#v for %q, but %#v:", testcase.expected, testcase.line, args)
}
for i, testcase := range testcases {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
args, err := Parse(testcase.line)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(args, testcase.expected) {
t.Fatalf("Expected %#v for %q, but %#v:", testcase.expected, testcase.line, args)
}
})
}
}

Expand All @@ -64,52 +63,6 @@ func TestError(t *testing.T) {
}
}

func TestShellRun(t *testing.T) {
dir, err := os.Getwd()
if err != nil {
t.Fatal(err)
}

pwd, err := shellRun("pwd", "")
if err != nil {
t.Fatal(err)
}

pwd2, err := shellRun("pwd", path.Join(dir, "/_example"))
if err != nil {
t.Fatal(err)
}

if pwd == pwd2 {
t.Fatal("`pwd` should be changed")
}
}

func TestShellRunNoEnv(t *testing.T) {
old := os.Getenv("SHELL")
defer os.Setenv("SHELL", old)
os.Unsetenv("SHELL")

dir, err := os.Getwd()
if err != nil {
t.Fatal(err)
}

pwd, err := shellRun("pwd", "")
if err != nil {
t.Fatal(err)
}

pwd2, err := shellRun("pwd", path.Join(dir, "/_example"))
if err != nil {
t.Fatal(err)
}

if pwd == pwd2 {
t.Fatal("`pwd` should be changed")
}
}

func TestBacktick(t *testing.T) {
goversion, err := shellRun("go version", "")
if err != nil {
Expand Down
78 changes: 78 additions & 0 deletions shellwords_windows_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package shellwords

import (
"fmt"
"os"
"path"
"reflect"
"testing"
)

func TestEscaping(t *testing.T) {
var testcases = []struct {
line string
expected []string
}{
{"foo bar\\ ", []string{`foo`, `bar\`}},
{`\\uncpath foo`, []string{`\\uncpath`, `foo`}},
{`upx c:\github.com\jftuga\test\test.exe`, []string{`upx`, `c:\github.com\jftuga\test\test.exe`}},
}

for i, testcase := range testcases {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
args, err := Parse(testcase.line)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(args, testcase.expected) {
t.Fatalf("Expected %#v for %q, but %#v:", testcase.expected, testcase.line, args)
}
})
}
}

func TestShellRun(t *testing.T) {
dir, err := os.Getwd()
if err != nil {
t.Fatal(err)
}

pwd, err := shellRun("dir", "")
if err != nil {
t.Fatal(err)
}

pwd2, err := shellRun("dir", path.Join(dir, "/_example"))
if err != nil {
t.Fatal(err)
}

if pwd == pwd2 {
t.Fatal("`dir` should be changed")
}
}

func TestShellRunNoEnv(t *testing.T) {
old := os.Getenv("COMSPEC")
defer os.Setenv("COMSPEC", old)
os.Unsetenv("COMSPEC")

dir, err := os.Getwd()
if err != nil {
t.Fatal(err)
}

pwd, err := shellRun("dir", "")
if err != nil {
t.Fatal(err)
}

pwd2, err := shellRun("dir", path.Join(dir, "/_example"))
if err != nil {
t.Fatal(err)
}

if pwd == pwd2 {
t.Fatal("`dir` should be changed")
}
}
4 changes: 4 additions & 0 deletions util_posix.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,7 @@ func shellRun(line, dir string) (string, error) {
}
return strings.TrimSpace(string(b)), nil
}

func isEscapeRune(r rune) bool {
return r == '\\'
}
5 changes: 5 additions & 0 deletions util_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,8 @@ func shellRun(line, dir string) (string, error) {
}
return strings.TrimSpace(string(b)), nil
}

func isEscapeRune(r rune) bool {
// TODO: Implement escaping (via `) on Windows
return false
}

0 comments on commit 661cffe

Please sign in to comment.