220 lines
6 KiB
Go
220 lines
6 KiB
Go
|
|
package glob
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"errors"
|
|||
|
|
"fmt"
|
|||
|
|
"reflect"
|
|||
|
|
"strings"
|
|||
|
|
"testing"
|
|||
|
|
"testing/fstest"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
type test struct {
|
|||
|
|
pattern, f string
|
|||
|
|
match bool
|
|||
|
|
err error
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func escape(name string) string {
|
|||
|
|
// use a math division slash for correct visual
|
|||
|
|
return strings.ReplaceAll(name, "/", "∕")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func TestPattern_Match(t *testing.T) {
|
|||
|
|
tests := []test{
|
|||
|
|
// Test cases not covered by path.Match
|
|||
|
|
{"main.go", "main.go", true, nil},
|
|||
|
|
{"main_test.go", "main_test.go", true, nil},
|
|||
|
|
{"foo/foo_test.go", "foo/foo_test.go", true, nil},
|
|||
|
|
{"?.go", "m.go", true, nil},
|
|||
|
|
{"*.go", "main.go", true, nil},
|
|||
|
|
{"**/*.go", "main.go", true, nil},
|
|||
|
|
{"*.go", "*.go", true, nil},
|
|||
|
|
|
|||
|
|
{"//", "", false, ErrBadPattern},
|
|||
|
|
{"foo//", "", false, ErrBadPattern},
|
|||
|
|
{"*?.go", "", false, ErrBadPattern},
|
|||
|
|
{"?*.go", "", false, ErrBadPattern},
|
|||
|
|
{"**?.go", "", false, ErrBadPattern},
|
|||
|
|
{"**f", "", false, ErrBadPattern},
|
|||
|
|
{"[a-", "", false, ErrBadPattern},
|
|||
|
|
{"[a-\\", "", false, ErrBadPattern},
|
|||
|
|
{"[\\", "", false, ErrBadPattern},
|
|||
|
|
|
|||
|
|
{"**/m.go", "foo.go", false, nil},
|
|||
|
|
{"**/m.go", "foo/a.go", false, nil},
|
|||
|
|
{"**/m.go", "m.go", true, nil},
|
|||
|
|
{"**/m.go", "foo/m.go", true, nil},
|
|||
|
|
{"**/m.go", "bar/m.go", true, nil},
|
|||
|
|
{"**/m.go", "foo/bar/m.go", true, nil},
|
|||
|
|
|
|||
|
|
{"ab[cde]", "abc", true, nil},
|
|||
|
|
{"ab[cde]", "abd", true, nil},
|
|||
|
|
{"ab[cde]", "abe", true, nil},
|
|||
|
|
{"ab[+-\\-]", "ab-", true, nil},
|
|||
|
|
{"ab[\\--a]", "ab-", true, nil},
|
|||
|
|
|
|||
|
|
{"[a-fA-F]", "a", true, nil},
|
|||
|
|
{"[a-fA-F]", "f", true, nil},
|
|||
|
|
{"[a-fA-F]", "A", true, nil},
|
|||
|
|
{"[a-fA-F]", "F", true, nil},
|
|||
|
|
|
|||
|
|
// The following test cases are taken from
|
|||
|
|
// https://github.com/golang/go/blob/master/src/path/match_test.go and are
|
|||
|
|
// provided here to test compatebility of the match implementation with the
|
|||
|
|
// test cases from the golang standard lib.
|
|||
|
|
{"abc", "abc", true, nil},
|
|||
|
|
{"*", "abc", true, nil},
|
|||
|
|
{"*c", "abc", true, nil},
|
|||
|
|
{"a*", "a", true, nil},
|
|||
|
|
{"a*", "abc", true, nil},
|
|||
|
|
{"a*", "ab/c", false, nil},
|
|||
|
|
{"a*/b", "abc/b", true, nil},
|
|||
|
|
{"a*/b", "a/c/b", false, nil},
|
|||
|
|
{"a*b*c*d*e*/f", "axbxcxdxe/f", true, nil},
|
|||
|
|
{"a*b*c*d*e*/f", "axbxcxdxexxx/f", true, nil},
|
|||
|
|
{"a*b*c*d*e*/f", "axbxcxdxe/xxx/f", false, nil},
|
|||
|
|
{"a*b*c*d*e*/f", "axbxcxdxexxx/fff", false, nil},
|
|||
|
|
{"a*b?c*x", "abxbbxdbxebxczzx", true, nil},
|
|||
|
|
{"a*b?c*x", "abxbbxdbxebxczzy", false, nil},
|
|||
|
|
{"ab[c]", "abc", true, nil},
|
|||
|
|
{"ab[b-d]", "abc", true, nil},
|
|||
|
|
{"ab[e-g]", "abc", false, nil},
|
|||
|
|
{"ab[^c]", "abc", false, nil},
|
|||
|
|
{"ab[^b-d]", "abc", false, nil},
|
|||
|
|
{"ab[^e-g]", "abc", true, nil},
|
|||
|
|
{"a\\*b", "a*b", true, nil},
|
|||
|
|
{"a\\*b", "ab", false, nil},
|
|||
|
|
{"a?b", "a☺b", true, nil},
|
|||
|
|
{"a[^a]b", "a☺b", true, nil},
|
|||
|
|
{"a???b", "a☺b", false, nil},
|
|||
|
|
{"a[^a][^a][^a]b", "a☺b", false, nil},
|
|||
|
|
{"[a-ζ]*", "α", true, nil},
|
|||
|
|
{"*[a-ζ]", "A", false, nil},
|
|||
|
|
{"a?b", "a/b", false, nil},
|
|||
|
|
{"a*b", "a/b", false, nil},
|
|||
|
|
{"[\\]a]", "]", true, nil},
|
|||
|
|
{"[\\-]", "-", true, nil},
|
|||
|
|
{"[x\\-]", "x", true, nil},
|
|||
|
|
{"[x\\-]", "-", true, nil},
|
|||
|
|
{"[x\\-]", "z", false, nil},
|
|||
|
|
{"[\\-x]", "x", true, nil},
|
|||
|
|
{"[\\-x]", "-", true, nil},
|
|||
|
|
{"[\\-x]", "a", false, nil},
|
|||
|
|
{"[]a]", "]", false, ErrBadPattern},
|
|||
|
|
{"[-]", "-", false, ErrBadPattern},
|
|||
|
|
{"[x-]", "x", false, ErrBadPattern},
|
|||
|
|
{"[x-]", "-", false, ErrBadPattern},
|
|||
|
|
{"[x-]", "z", false, ErrBadPattern},
|
|||
|
|
{"[-x]", "x", false, ErrBadPattern},
|
|||
|
|
{"[-x]", "-", false, ErrBadPattern},
|
|||
|
|
{"[-x]", "a", false, ErrBadPattern},
|
|||
|
|
{"\\", "a", false, ErrBadPattern},
|
|||
|
|
{"[a-b-c]", "a", false, ErrBadPattern},
|
|||
|
|
{"[", "a", false, ErrBadPattern},
|
|||
|
|
{"[^", "a", false, ErrBadPattern},
|
|||
|
|
{"[^bc", "a", false, ErrBadPattern},
|
|||
|
|
{"a[", "a", false, ErrBadPattern},
|
|||
|
|
{"a[", "ab", false, ErrBadPattern},
|
|||
|
|
{"a[", "x", false, ErrBadPattern},
|
|||
|
|
{"a/b[", "x", false, ErrBadPattern},
|
|||
|
|
{"*x", "xxx", true, nil},
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for _, tt := range tests {
|
|||
|
|
pat, err := New(tt.pattern)
|
|||
|
|
if err != tt.err && !errors.Is(err, tt.err) {
|
|||
|
|
t.Errorf("New(%#q): wanted error %v but got %v", tt.pattern, tt.err, err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if pat != nil {
|
|||
|
|
match := pat.Match(tt.f)
|
|||
|
|
if match != tt.match {
|
|||
|
|
t.Errorf("New(%#q).Match(%#q): wanted match %v but got %v", tt.pattern, tt.f, tt.match, match)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func TestPattern_MatchPrefix(t *testing.T) {
|
|||
|
|
tests := []test{
|
|||
|
|
{"**/*.go", "foo/", true, nil},
|
|||
|
|
{"**/*.go", "foo", true, nil},
|
|||
|
|
{"**/*.go", "foo/bar/", true, nil},
|
|||
|
|
{"**/*.go", "foo/bar", true, nil},
|
|||
|
|
{"*/*.go", "foo", true, nil},
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for _, tc := range tests {
|
|||
|
|
tc := tc // capture range variable
|
|||
|
|
t.Run(fmt.Sprintf("%s (%s)", escape(tc.pattern), escape(tc.f)), func(t *testing.T) {
|
|||
|
|
pat, err := New(tc.pattern)
|
|||
|
|
if err != nil {
|
|||
|
|
t.Errorf("unexpected error: %v", err)
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
got := pat.MatchPrefix(tc.f)
|
|||
|
|
|
|||
|
|
if got != tc.match {
|
|||
|
|
t.Errorf("got %v; want %v", got, tc.match)
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func TestPattern_GlobFS(t *testing.T) {
|
|||
|
|
fsys := fstest.MapFS{
|
|||
|
|
"go.mod": &fstest.MapFile{Mode: 0644},
|
|||
|
|
"go.sum": &fstest.MapFile{Mode: 0644},
|
|||
|
|
"cmd/main.go": &fstest.MapFile{Mode: 0644},
|
|||
|
|
"cmd/main_test.go": &fstest.MapFile{Mode: 0644},
|
|||
|
|
"internal/tool/tool.go": &fstest.MapFile{Mode: 0644},
|
|||
|
|
"internal/tool/tool_test.go": &fstest.MapFile{Mode: 0644},
|
|||
|
|
"internal/cli/cli.go": &fstest.MapFile{Mode: 0644},
|
|||
|
|
"internal/cli/cli_test.go": &fstest.MapFile{Mode: 0644},
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
pat, err := New("**/*_test.go")
|
|||
|
|
if err != nil {
|
|||
|
|
t.Fatal(err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
files, err := pat.GlobFS(fsys, ".")
|
|||
|
|
if err != nil {
|
|||
|
|
t.Fatal(err)
|
|||
|
|
}
|
|||
|
|
expect := []string{
|
|||
|
|
"cmd/main_test.go",
|
|||
|
|
"internal/cli/cli_test.go",
|
|||
|
|
"internal/tool/tool_test.go",
|
|||
|
|
}
|
|||
|
|
if !reflect.DeepEqual(expect, files) {
|
|||
|
|
t.Errorf("got %v; want %v", files, expect)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func TestPattern_String(t *testing.T) {
|
|||
|
|
tests := []string{
|
|||
|
|
"main.go",
|
|||
|
|
"*.go",
|
|||
|
|
"**/*.go",
|
|||
|
|
"foo/bar/*",
|
|||
|
|
"foo/?ar.go",
|
|||
|
|
"foo/[abc].go",
|
|||
|
|
"foo/[a-c].go",
|
|||
|
|
"foo/**/",
|
|||
|
|
"foo/*/bar.go",
|
|||
|
|
"foo/\\*bar.go",
|
|||
|
|
}
|
|||
|
|
for _, patstr := range tests {
|
|||
|
|
t.Run(escape(patstr), func(t *testing.T) {
|
|||
|
|
pat, err := New(patstr)
|
|||
|
|
if err != nil {
|
|||
|
|
t.Fatalf("New(%q) failed: %v", patstr, err)
|
|||
|
|
}
|
|||
|
|
if pat.String() != patstr {
|
|||
|
|
t.Fatalf("Pattern.String() = %q, want %q", pat.String(), patstr)
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|