diff --git a/mapper.go b/mapper.go index e8778ee..daf09bd 100644 --- a/mapper.go +++ b/mapper.go @@ -721,12 +721,15 @@ func SplitEscaped(s string, sep rune) (out []string) { } escaped := false token := "" - for _, ch := range s { + for i, ch := range s { switch { case escaped: + if ch != sep { + token += `\` + } token += string(ch) escaped = false - case ch == '\\': + case ch == '\\' && i < len(s)-1: escaped = true case ch == sep && !escaped: out = append(out, token) diff --git a/mapper_linux_test.go b/mapper_linux_test.go new file mode 100644 index 0000000..8148e24 --- /dev/null +++ b/mapper_linux_test.go @@ -0,0 +1,26 @@ +//go:build !windows +// +build !windows + +package kong_test + +import ( + "os" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestPathMapper(t *testing.T) { + var cli struct { + Path string `arg:"" type:"path"` + } + p := mustNew(t, &cli) + + _, err := p.Parse([]string{"/an/absolute/path"}) + require.NoError(t, err) + require.Equal(t, "/an/absolute/path", cli.Path) + + _, err = p.Parse([]string{"-"}) + require.NoError(t, err) + require.Equal(t, "-", cli.Path) +} diff --git a/mapper_test.go b/mapper_test.go index fdd7c8e..c162cb8 100644 --- a/mapper_test.go +++ b/mapper_test.go @@ -9,6 +9,7 @@ import ( "net/url" "os" "reflect" + "runtime" "strings" "testing" "time" @@ -412,27 +413,16 @@ func TestFileMapper(t *testing.T) { _ = cli.File.Close() _, err = p.Parse([]string{"testdata/missing.txt"}) require.Error(t, err) - require.Contains(t, err.Error(), "missing.txt: no such file or directory") + if runtime.GOOS == "windows" { + require.Contains(t, err.Error(), "missing.txt: The system cannot find the file specified.") + } else { + require.Contains(t, err.Error(), "missing.txt: no such file or directory") + } _, err = p.Parse([]string{"-"}) require.NoError(t, err) require.Equal(t, os.Stdin, cli.File) } -func TestPathMapper(t *testing.T) { - var cli struct { - Path string `arg:"" type:"path"` - } - p := mustNew(t, &cli) - - _, err := p.Parse([]string{"/an/absolute/path"}) - require.NoError(t, err) - require.Equal(t, "/an/absolute/path", cli.Path) - - _, err = p.Parse([]string{"-"}) - require.NoError(t, err) - require.Equal(t, "-", cli.Path) -} - func TestMapperPlaceHolder(t *testing.T) { var cli struct { Flag string diff --git a/mapper_windows_test.go b/mapper_windows_test.go new file mode 100644 index 0000000..039e9ec --- /dev/null +++ b/mapper_windows_test.go @@ -0,0 +1,44 @@ +//go:build windows +// +build windows + +package kong_test + +import ( + "os" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestWindowsPathMapper(t *testing.T) { + var cli struct { + Path string `short:"p" type:"path"` + Files []string `short:"f" type:"path"` + } + wd, err := os.Getwd() + require.NoError(t, err, "Getwd failed") + p := mustNew(t, &cli) + + _, err = p.Parse([]string{`-p`, `c:\an\absolute\path`, `-f`, `c:\second\absolute\path\`, `-f`, `relative\path\file`}) + require.NoError(t, err) + require.Equal(t, `c:\an\absolute\path`, cli.Path) + require.Equal(t, []string{`c:\second\absolute\path\`, wd + `\relative\path\file`}, cli.Files) +} + +func TestWindowsFileMapper(t *testing.T) { + type CLI struct { + File *os.File `arg:""` + } + var cli CLI + p := mustNew(t, &cli) + _, err := p.Parse([]string{"testdata\\file.txt"}) + require.NoError(t, err) + require.NotNil(t, cli.File) + _ = cli.File.Close() + _, err = p.Parse([]string{"testdata\\missing.txt"}) + require.Error(t, err) + require.Contains(t, err.Error(), "missing.txt: The system cannot find the file specified.") + _, err = p.Parse([]string{"-"}) + require.NoError(t, err) + require.Equal(t, os.Stdin, cli.File) +} diff --git a/util_test.go b/util_test.go index 5bf586f..77ccb99 100644 --- a/util_test.go +++ b/util_test.go @@ -4,6 +4,7 @@ import ( "io/ioutil" "os" "path/filepath" + "runtime" "strings" "testing" @@ -62,7 +63,9 @@ func TestChangeDirFlag(t *testing.T) { p := Must(&cli) _, err = p.Parse([]string{"-C", dir, "out.txt"}) require.NoError(t, err) - file, err = filepath.EvalSymlinks(file) // Needed because OSX uses a symlinked tmp dir. - require.NoError(t, err) + if runtime.GOOS != "windows" { + file, err = filepath.EvalSymlinks(file) // Needed because OSX uses a symlinked tmp dir. + require.NoError(t, err) + } require.Equal(t, file, cli.Path) }