Crosspath: add ToNative() function

Add `crosspath.ToNative(path)`, which returns the path with platform-
native path separators. This is meant for use in the Worker, to convert
paths before attempting to use them.
This commit is contained in:
Sybren A. Stüvel 2022-03-04 11:10:10 +01:00
parent 70f8140df5
commit 3c6d7773ef
2 changed files with 82 additions and 0 deletions

@ -25,7 +25,9 @@ package crosspath
* ***** END GPL LICENSE BLOCK ***** */
import (
"fmt"
path_module "path" // import under other name so that parameters can be called 'path'
"path/filepath"
"strings"
)
@ -78,3 +80,16 @@ func Stem(path string) string {
func ToSlash(path string) string {
return strings.ReplaceAll(path, "\\", "/")
}
// ToNative replaces all path separators (forward and backward slashes) with the
// platform-native separator.
func ToNative(path string) string {
switch filepath.Separator {
case '/':
return ToSlash(path)
case '\\':
return strings.ReplaceAll(path, "/", "\\")
default:
panic(fmt.Sprintf("this platform has an unknown path separator: %q", filepath.Separator))
}
}

@ -22,6 +22,8 @@ package crosspath
import (
"path"
"path/filepath"
"runtime"
"testing"
"github.com/stretchr/testify/assert"
@ -35,6 +37,7 @@ func TestBase(t *testing.T) {
{"justafile.txt", "justafile.txt"},
{"with spaces.txt", "/Linux path/with spaces.txt"},
{"awésom.tar.gz", "C:\\ünicode\\is\\awésom.tar.gz"},
{"Resource with ext.ension", "\\\\?\\UNC\\ComputerName\\SharedFolder\\Resource with ext.ension"},
}
for _, test := range tests {
assert.Equal(t, test.expect, Base(test.input))
@ -120,3 +123,67 @@ func TestStem(t *testing.T) {
"for input %q", test.input)
}
}
func TestToNative_native_backslash(t *testing.T) {
if filepath.Separator != '\\' {
t.Skipf("skipping backslash-specific test on %q with path separator %q",
runtime.GOOS, filepath.Separator)
}
tests := []struct {
expect, input string
}{
{"", ""},
{".", "."},
{"\\some\\simple\\path", "/some/simple/path"},
{"C:\\path\\to\\file.txt", "C:\\path\\to\\file.txt"},
{"C:\\path\\to\\mixed\\slashes\\file.txt", "C:\\path\\to/mixed/slashes/file.txt"},
{"\\\\?\\UNC\\ComputerName\\SharedFolder\\Resource with ext.ension",
"\\\\?\\UNC\\ComputerName\\SharedFolder\\Resource with ext.ension"},
{"\\\\?\\UNC\\ComputerName\\SharedFolder\\Resource with ext.ension",
"//?/UNC/ComputerName/SharedFolder/Resource with ext.ension"},
}
for _, test := range tests {
assert.Equal(t,
test.expect, ToNative(test.input),
"for input %q", test.input)
}
}
func TestToNative_native_slash(t *testing.T) {
if filepath.Separator != '/' {
t.Skipf("skipping backslash-specific test on %q with path separator %q",
runtime.GOOS, filepath.Separator)
}
tests := []struct {
expect, input string
}{
{"", ""},
{".", "."},
{"/some/simple/path", "/some/simple/path"},
{"C:/path/to/file.txt", "C:\\path\\to\\file.txt"},
{"C:/path/to/mixed/slashes/file.txt", "C:\\path\\to/mixed/slashes/file.txt"},
{"//?/UNC/ComputerName/SharedFolder/Resource with ext.ension",
"\\\\?\\UNC\\ComputerName\\SharedFolder\\Resource with ext.ension"},
{"//?/UNC/ComputerName/SharedFolder/Resource with ext.ension",
"//?/UNC/ComputerName/SharedFolder/Resource with ext.ension"},
}
for _, test := range tests {
assert.Equal(t,
test.expect, ToNative(test.input),
"for input %q", test.input)
}
}
// This test should be skipped on every platform. It's there just to detect that
// the above two tests haven't run.
func TestToNative_unsupported(t *testing.T) {
if filepath.Separator == '/' || filepath.Separator == '\\' {
t.Skipf("skipping test on %q with path separator %q",
runtime.GOOS, filepath.Separator)
}
t.Fatalf("ToNative not supported on this platform %q with path separator %q",
runtime.GOOS, filepath.Separator)
}