diff --git a/pkg/fileutils/fileutils.go b/pkg/fileutils/fileutils.go index 7ff340602e..d630795359 100644 --- a/pkg/fileutils/fileutils.go +++ b/pkg/fileutils/fileutils.go @@ -313,7 +313,7 @@ func (p *Pattern) Exclusion() bool { func (p *Pattern) match(path string) (bool, error) { if p.matchType == unknownMatch { - if err := p.compile(); err != nil { + if err := p.compile(string(os.PathSeparator)); err != nil { return false, filepath.ErrBadPattern } } @@ -339,7 +339,7 @@ func (p *Pattern) match(path string) (bool, error) { return false, nil } -func (p *Pattern) compile() error { +func (p *Pattern) compile(sl string) error { regStr := "^" pattern := p.cleanedPattern // Go through the pattern and convert it to a regexp. @@ -347,7 +347,6 @@ func (p *Pattern) compile() error { var scan scanner.Scanner scan.Init(strings.NewReader(pattern)) - sl := string(os.PathSeparator) escSL := sl if sl == `\` { escSL += `\` diff --git a/pkg/fileutils/fileutils_test.go b/pkg/fileutils/fileutils_test.go index c1b720a0db..f517e1522c 100644 --- a/pkg/fileutils/fileutils_test.go +++ b/pkg/fileutils/fileutils_test.go @@ -675,7 +675,7 @@ func errp(e error) string { return e.Error() } -// TestMatch test's our version of filepath.Match, called regexpMatch. +// TestMatch tests our version of filepath.Match, called Matches. func TestMatch(t *testing.T) { for _, tt := range matchTests { pattern := tt.pattern @@ -694,3 +694,73 @@ func TestMatch(t *testing.T) { } } } + +type compileTestCase struct { + pattern string + matchType matchType + compiledRegexp string + windowsCompiledRegexp string +} + +var compileTests = []compileTestCase{ + {"*", regexpMatch, `^[^/]*$`, `^[^\\]*$`}, + {"file*", regexpMatch, `^file[^/]*$`, `^file[^\\]*$`}, + {"*file", regexpMatch, `^[^/]*file$`, `^[^\\]*file$`}, + {"a*/b", regexpMatch, `^a[^/]*/b$`, `^a[^\\]*\\b$`}, + {"**", suffixMatch, "", ""}, + {"**/**", regexpMatch, `^(.*/)?.*$`, `^(.*\\)?.*$`}, + {"dir/**", prefixMatch, "", ""}, + {"**/dir", suffixMatch, "", ""}, + {"**/dir2/*", regexpMatch, `^(.*/)?dir2/[^/]*$`, `^(.*\\)?dir2\\[^\\]*$`}, + {"**/dir2/**", regexpMatch, `^(.*/)?dir2/.*$`, `^(.*\\)?dir2\\.*$`}, + {"**file", suffixMatch, "", ""}, + {"**/file*txt", regexpMatch, `^(.*/)?file[^/]*txt$`, `^(.*\\)?file[^\\]*txt$`}, + {"**/**/*.txt", regexpMatch, `^(.*/)?(.*/)?[^/]*\.txt$`, `^(.*\\)?(.*\\)?[^\\]*\.txt$`}, + {"a[b-d]e", regexpMatch, `^a[b-d]e$`, `^a[b-d]e$`}, + {".*", regexpMatch, `^\.[^/]*$`, `^\.[^\\]*$`}, + {"abc.def", exactMatch, "", ""}, + {"abc?def", regexpMatch, `^abc[^/]def$`, `^abc[^\\]def$`}, + {"**/foo/bar", suffixMatch, "", ""}, + {"a(b)c/def", exactMatch, "", ""}, + {"a.|)$(}+{bc", exactMatch, "", ""}, + {"dist/proxy.py-2.4.0rc3.dev36+g08acad9-py3-none-any.whl", exactMatch, "", ""}, +} + +// TestCompile confirms that "compile" assigns the correct match type to a +// variety of test case patterns. If the match type is regexp, it also confirms +// that the compiled regexp matches the expected regexp. +func TestCompile(t *testing.T) { + t.Run("slash", testCompile("/")) + t.Run("backslash", testCompile(`\`)) +} + +func testCompile(sl string) func(*testing.T) { + return func(t *testing.T) { + for _, tt := range compileTests { + pattern := tt.pattern + if sl != "/" { + pattern = strings.ReplaceAll(pattern, "/", sl) + } + pm, err := NewPatternMatcher([]string{pattern}) + if err != nil { + t.Fatalf("Failed to create PatternMatcher for pattern %q: %v", pattern, err) + } + if err := pm.patterns[0].compile(sl); err != nil { + t.Fatalf("Failed to compile pattern %q: %v", pattern, err) + } + if pm.patterns[0].matchType != tt.matchType { + t.Errorf("pattern %q: matchType = %v, want %v", pattern, pm.patterns[0].matchType, tt.matchType) + continue + } + if tt.matchType == regexpMatch { + if sl == `\` { + if pm.patterns[0].regexp.String() != tt.windowsCompiledRegexp { + t.Errorf("pattern %q: regexp = %s, want %s", pattern, pm.patterns[0].regexp, tt.windowsCompiledRegexp) + } + } else if pm.patterns[0].regexp.String() != tt.compiledRegexp { + t.Errorf("pattern %q: regexp = %s, want %s", pattern, pm.patterns[0].regexp, tt.compiledRegexp) + } + } + } + } +}