blob: 7c1987766635c8b291eda6c3344ff1eecb000156 [file] [log] [blame]
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package str
import (
"os"
"path/filepath"
"runtime"
"strings"
"testing"
)
var foldDupTests = []struct {
list []string
f1, f2 string
}{
{StringList("math/rand", "math/big"), "", ""},
{StringList("math", "strings"), "", ""},
{StringList("strings"), "", ""},
{StringList("strings", "strings"), "strings", "strings"},
{StringList("Rand", "rand", "math", "math/rand", "math/Rand"), "Rand", "rand"},
}
func TestFoldDup(t *testing.T) {
for _, tt := range foldDupTests {
f1, f2 := FoldDup(tt.list)
if f1 != tt.f1 || f2 != tt.f2 {
t.Errorf("foldDup(%q) = %q, %q, want %q, %q", tt.list, f1, f2, tt.f1, tt.f2)
}
}
}
func TestHasPathPrefix(t *testing.T) {
type testCase struct {
s, prefix string
want bool
}
for _, tt := range []testCase{
{"", "", true},
{"", "/", false},
{"foo", "", true},
{"foo", "/", false},
{"foo", "foo", true},
{"foo", "foo/", false},
{"foo", "/foo", false},
{"foo/bar", "", true},
{"foo/bar", "foo", true},
{"foo/bar", "foo/", true},
{"foo/bar", "/foo", false},
{"foo/bar", "foo/bar", true},
{"foo/bar", "foo/bar/", false},
{"foo/bar", "/foo/bar", false},
} {
got := HasPathPrefix(tt.s, tt.prefix)
if got != tt.want {
t.Errorf("HasPathPrefix(%q, %q) = %v; want %v", tt.s, tt.prefix, got, tt.want)
}
}
}
func TestTrimFilePathPrefixSlash(t *testing.T) {
if os.PathSeparator != '/' {
t.Skipf("test requires slash-separated file paths")
}
type testCase struct {
s, prefix, want string
}
for _, tt := range []testCase{
{"/", "", "/"},
{"/", "/", ""},
{"/foo", "", "/foo"},
{"/foo", "/", "foo"},
{"/foo", "/foo", ""},
{"/foo/bar", "/foo", "bar"},
{"/foo/bar", "/foo/", "bar"},
{"/foo/", "/", "foo/"},
{"/foo/", "/foo", ""},
{"/foo/", "/foo/", ""},
// if prefix is not s's prefix, return s
{"", "/", ""},
{"/foo", "/bar", "/foo"},
{"/foo", "/foo/bar", "/foo"},
{"foo", "/foo", "foo"},
{"/foo", "foo", "/foo"},
{"/foo", "/foo/", "/foo"},
} {
got := TrimFilePathPrefix(tt.s, tt.prefix)
if got == tt.want {
t.Logf("TrimFilePathPrefix(%q, %q) = %q", tt.s, tt.prefix, got)
} else {
t.Errorf("TrimFilePathPrefix(%q, %q) = %q, want %q", tt.s, tt.prefix, got, tt.want)
}
if HasFilePathPrefix(tt.s, tt.prefix) {
joined := filepath.Join(tt.prefix, got)
if clean := filepath.Clean(tt.s); joined != clean {
t.Errorf("filepath.Join(%q, %q) = %q, want %q", tt.prefix, got, joined, clean)
}
}
}
}
func TestTrimFilePathPrefixWindows(t *testing.T) {
if runtime.GOOS != "windows" {
t.Skipf("test requires Windows file paths")
}
type testCase struct {
s, prefix, want string
}
for _, tt := range []testCase{
{`\`, ``, `\`},
{`\`, `\`, ``},
{`C:`, `C:`, ``},
{`C:\`, `C:`, `\`},
{`C:\`, `C:\`, ``},
{`C:\foo`, ``, `C:\foo`},
{`C:\foo`, `C:`, `\foo`},
{`C:\foo`, `C:\`, `foo`},
{`C:\foo`, `C:\foo`, ``},
{`C:\foo\`, `C:\foo`, ``},
{`C:\foo\bar`, `C:\foo`, `bar`},
{`C:\foo\bar`, `C:\foo\`, `bar`},
// if prefix is not s's prefix, return s
{`C:\foo`, `C:\bar`, `C:\foo`},
{`C:\foo`, `C:\foo\bar`, `C:\foo`},
{`C:`, `C:\`, `C:`},
// if volumes are different, return s
{`C:`, ``, `C:`},
{`C:\`, ``, `C:\`},
{`C:\foo`, ``, `C:\foo`},
{`C:\foo`, `\foo`, `C:\foo`},
{`C:\foo`, `D:\foo`, `C:\foo`},
//UNC path
{`\\host\share\foo`, `\\host\share`, `foo`},
{`\\host\share\foo`, `\\host\share\`, `foo`},
{`\\host\share\foo`, `\\host\share\foo`, ``},
{`\\host\share\foo\bar`, `\\host\share\foo`, `bar`},
{`\\host\share\foo\bar`, `\\host\share\foo\`, `bar`},
// if prefix is not s's prefix, return s
{`\\host\share\foo`, `\\host\share\bar`, `\\host\share\foo`},
{`\\host\share\foo`, `\\host\share\foo\bar`, `\\host\share\foo`},
// if either host or share name is different, return s
{`\\host\share\foo`, ``, `\\host\share\foo`},
{`\\host\share\foo`, `\foo`, `\\host\share\foo`},
{`\\host\share\foo`, `\\host\other\`, `\\host\share\foo`},
{`\\host\share\foo`, `\\other\share\`, `\\host\share\foo`},
{`\\host\share\foo`, `\\host\`, `\\host\share\foo`},
{`\\host\share\foo`, `\share\`, `\\host\share\foo`},
// only volume names are case-insensitive
{`C:\foo`, `c:`, `\foo`},
{`C:\foo`, `c:\foo`, ``},
{`c:\foo`, `C:`, `\foo`},
{`c:\foo`, `C:\foo`, ``},
{`C:\foo`, `C:\Foo`, `C:\foo`},
{`\\Host\Share\foo`, `\\host\share`, `foo`},
{`\\Host\Share\foo`, `\\host\share\foo`, ``},
{`\\host\share\foo`, `\\Host\Share`, `foo`},
{`\\host\share\foo`, `\\Host\Share\foo`, ``},
{`\\Host\Share\foo`, `\\Host\Share\Foo`, `\\Host\Share\foo`},
} {
got := TrimFilePathPrefix(tt.s, tt.prefix)
if got == tt.want {
t.Logf("TrimFilePathPrefix(%#q, %#q) = %#q", tt.s, tt.prefix, got)
} else {
t.Errorf("TrimFilePathPrefix(%#q, %#q) = %#q, want %#q", tt.s, tt.prefix, got, tt.want)
}
if HasFilePathPrefix(tt.s, tt.prefix) {
// Although TrimFilePathPrefix is only case-insensitive in the volume name,
// what we care about in testing Join is that absolute paths remain
// absolute and relative paths remaining relative — there is no harm in
// over-normalizing letters in the comparison, so we use EqualFold.
joined := filepath.Join(tt.prefix, got)
if clean := filepath.Clean(tt.s); !strings.EqualFold(joined, clean) {
t.Errorf("filepath.Join(%#q, %#q) = %#q, want %#q", tt.prefix, got, joined, clean)
}
}
}
}