From 3c6d7773eff8e2df48beabbb051dee5c2847d988 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Fri, 4 Mar 2022 11:10:10 +0100 Subject: [PATCH] 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. --- pkg/crosspath/crosspath.go | 15 ++++++++ pkg/crosspath/crosspath_test.go | 67 +++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/pkg/crosspath/crosspath.go b/pkg/crosspath/crosspath.go index 6ca8c6d9..8da08142 100644 --- a/pkg/crosspath/crosspath.go +++ b/pkg/crosspath/crosspath.go @@ -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)) + } +} diff --git a/pkg/crosspath/crosspath_test.go b/pkg/crosspath/crosspath_test.go index cae4dee5..5f53cef9 100644 --- a/pkg/crosspath/crosspath_test.go +++ b/pkg/crosspath/crosspath_test.go @@ -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) +}