sdk/glob/glob_test.go
Louis Seubert 24ad00274d
All checks were successful
default / ensure tests work (push) Successful in 35s
feat: rewrote glob to have a full doublestar impl
This implements a full double star glob implementation with it's own filesystem implementation.
2026-01-25 17:22:16 +01:00

220 lines
6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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)
}
})
}
}