75 lines
3.0 KiB
Go
75 lines
3.0 KiB
Go
package safepath
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestPathJoin(t *testing.T) {
|
|
orig := osSeparator
|
|
osSeparator = '\\' // pretend we're on Windows
|
|
defer func() { osSeparator = orig }()
|
|
|
|
testCases := []struct {
|
|
Comment string
|
|
In []string
|
|
Out any // string or error
|
|
}{
|
|
{"Empty elements should not change input", []string{"/test/"}, "/test"},
|
|
{"Empty elements without leading slash should not change input", []string{"test/"}, "test"},
|
|
{"Single element should be added to path", []string{"/test/", "abc"}, "/test/abc"},
|
|
{"Single element should be added to path with current dir prefix", []string{"./test/", "abc"}, "test/abc"},
|
|
{"Single element with leading slash should be added to path", []string{"/test/", "/abc"}, "/test/abc"},
|
|
{"Many elements are all appended to path", []string{"/test/", "a", "b", "c"}, "/test/a/b/c"},
|
|
{"Path traversal within same directory should be expanded", []string{"/test/", "a", "..", "b", ".", "..", "c"}, "/test/c"},
|
|
{"Path traversal escaping root dir prefix should return err", []string{"/test/", ".."}, ErrUnsafePathTraversal},
|
|
{"Path traversal escaping no dir prefix should return err", []string{"test/", ".."}, ErrUnsafePathTraversal},
|
|
{"Path traversal escaping current dir prefix should return err", []string{"./test/", ".."}, ErrUnsafePathTraversal},
|
|
{"Complex path traversal escaping prefix should return err", []string{"/test/", "a/..///c/", "../../test/d/../a/../.."}, ErrUnsafePathTraversal},
|
|
{"Complex path traversal remaining in prefix should be expanded", []string{"/test/", "a/..///c/", "../../test/d/"}, "/test/d"},
|
|
{"Problematic code example from the g304 website", []string{"/safe/path", "../../private/path"}, ErrUnsafePathTraversal},
|
|
{"Traversing beyond root should be expanded", []string{"/test/", "/../a"}, "/test/a"},
|
|
{"OS separator should be replaced with a slash", []string{"/test\\test", "abc\\test"}, "/test/test/abc/test"},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
tc := tc
|
|
t.Run(tc.Comment, func(t *testing.T) {
|
|
path, err := Join(tc.In[0], tc.In[1:]...)
|
|
if ee, ok := tc.Out.(error); ok {
|
|
assert.ErrorIs(t, err, ee, "expected unsuccessful outcome")
|
|
assert.Empty(t, path, "expected empty string when unsuccessful")
|
|
} else if str, ok := tc.Out.(string); ok {
|
|
assert.NoError(t, err, "expected successful outcome")
|
|
assert.Equal(t, str, path)
|
|
} else {
|
|
panic("expected out was neither string nor error")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestPathClean(t *testing.T) {
|
|
orig := osSeparator
|
|
osSeparator = '\\' // pretend we're on Windows
|
|
defer func() { osSeparator = orig }()
|
|
|
|
testCases := []struct {
|
|
Comment string
|
|
In string
|
|
Out string
|
|
}{
|
|
{"Simple path", "/test/", "/test"},
|
|
{"Simple path with OS separators", "\\test\\here", "/test/here"},
|
|
{"Simple path with mixed separators", "\\test/here", "/test/here"},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
tc := tc
|
|
t.Run(tc.Comment, func(t *testing.T) {
|
|
assert.Equal(t, tc.Out, Clean(tc.In))
|
|
})
|
|
}
|
|
}
|