Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix deep recursion on star end #127

Merged
merged 2 commits into from
Aug 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ellipses/ellipses_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ func TestFindEllipsesPatterns(t *testing.T) {
return s
}
if !reflect.DeepEqual(got, testCase.want) {
t.Errorf(fmt.Sprintf("want %s,", repl(testCase.want)))
t.Errorf("want %s,", repl(testCase.want))
t.Errorf("got %s,", repl(got))
}
}
Expand Down
2 changes: 1 addition & 1 deletion ellipses/list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ func TestFindListPatterns(t *testing.T) {
return s
}
if !reflect.DeepEqual(got, testCase.want) {
t.Errorf(fmt.Sprintf("want %s,", repl(testCase.want)))
t.Errorf("want %s,", repl(testCase.want))
t.Errorf("got %s,", repl(got))
}
}
Expand Down
15 changes: 6 additions & 9 deletions wildcard/match.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func MatchSimple(pattern, name string) bool {
return true
}
// Do an extended wildcard '*' and '?' match.
return deepMatchRune([]rune(name), []rune(pattern), true)
return deepMatchRune(name, pattern, true)
}

// Match - finds whether the text matches/satisfies the pattern string.
Expand All @@ -44,10 +44,10 @@ func Match(pattern, name string) (matched bool) {
return true
}
// Do an extended wildcard '*' and '?' match.
return deepMatchRune([]rune(name), []rune(pattern), false)
return deepMatchRune(name, pattern, false)
}

func deepMatchRune(str, pattern []rune, simple bool) bool {
func deepMatchRune(str, pattern string, simple bool) bool {
for len(pattern) > 0 {
switch pattern[0] {
default:
Expand All @@ -59,8 +59,9 @@ func deepMatchRune(str, pattern []rune, simple bool) bool {
return simple
}
case '*':
return deepMatchRune(str, pattern[1:], simple) ||
(len(str) > 0 && deepMatchRune(str[1:], pattern, simple))
return len(pattern) == 1 || // Pattern ends with this star
deepMatchRune(str, pattern[1:], simple) || // Matches next part of pattern
(len(str) > 0 && deepMatchRune(str[1:], pattern, simple)) // Continue searching forward
}
str = str[1:]
pattern = pattern[1:]
Expand All @@ -83,10 +84,6 @@ func deepMatchRune(str, pattern []rune, simple bool) bool {
//
// This function is only useful in some special situations.
func MatchAsPatternPrefix(pattern, text string) bool {
return matchAsPatternPrefix([]rune(pattern), []rune(text))
}

func matchAsPatternPrefix(pattern, text []rune) bool {
for i := 0; i < len(text) && i < len(pattern); i++ {
if pattern[i] == '*' {
return true
Expand Down
183 changes: 183 additions & 0 deletions wildcard/match_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
package wildcard

import (
"fmt"
"strings"
"testing"
)

Expand Down Expand Up @@ -552,6 +554,187 @@ func TestMatchSimple(t *testing.T) {
}
}

// BenchmarkMatchSimple - Tests validate the logic of wild card matching.
// `MatchSimple` supports matching for only '*' in the pattern string.
func BenchmarkMatchSimple(b *testing.B) {
testCases := []struct {
pattern string
text string
matched bool
}{
// Test case - 0.
{
pattern: "a*",
text: "aListMultipartUploadPartsListMultipartUploadPartsListMultipartUploadPartsListMultipartUploadPartsListMultipartUploadPartsListMultipartUploadPartsListMultipartUploadPartsListMultipartUploadPartsListMultipartUploadPartsListMultipartUploadPartsListMultipartUploadPartsListMultipartUploadPartsListMultipartUploadPartsListMultipartUploadPartsListMultipartUploadPartsListMultipartUploadPartsListMultipartUploadPartsListMultipartUploadPartsListMultipartUploadPartsListMultipartUploadPartsListMultipartUploadPartsListMultipartUploadPartsListMultipartUploadParts",
matched: true,
},
// Test case - 1.
// Test case with pattern "*". Expected to match any text.
{
pattern: "*",
text: "s3:GetObject",
matched: true,
},
// Test case - 2.
// Test case with empty pattern. This only matches empty string.
{
pattern: "",
text: "s3:GetObject",
matched: false,
},
// Test case - 3.
// Test case with empty pattern. This only matches empty string.
{
pattern: "",
text: "",
matched: true,
},
// Test case - 4.
// Test case with single "*" at the end.
{
pattern: "s3:*",
text: "s3:ListMultipartUploadParts",
matched: true,
},
// Test case - 5.
// Test case with a no "*". In this case the pattern and text should be the same.
{
pattern: "s3:ListBucketMultipartUploads",
text: "s3:ListBucket",
matched: false,
},
// Test case - 6.
// Test case with a no "*". In this case the pattern and text should be the same.
{
pattern: "s3:ListBucket",
text: "s3:ListBucket",
matched: true,
},
// Test case - 7.
// Test case with a no "*". In this case the pattern and text should be the same.
{
pattern: "s3:ListBucketMultipartUploads",
text: "s3:ListBucketMultipartUploads",
matched: true,
},
// Test case - 8.
// Test case with pattern containing key name with a prefix. Should accept the same text without a "*".
{
pattern: "my-bucket/oo*",
text: "my-bucket/oo",
matched: true,
},
// Test case - 9.
// Test case with "*" at the end of the pattern.
{
pattern: "my-bucket/In*",
text: "my-bucket/India/Karnataka/",
matched: true,
},
// Test case - 10.
// Test case with prefixes shuffled.
// This should fail.
{
pattern: "my-bucket/In*",
text: "my-bucket/Karnataka/India/",
matched: false,
},
// Test case - 11.
// Test case with text expanded to the wildcards in the pattern.
{
pattern: "my-bucket/In*/Ka*/Ban",
text: "my-bucket/India/Karnataka/Ban",
matched: true,
},
// Test case - 12.
// Test case with the keyname part is repeated as prefix several times.
// This is valid.
{
pattern: "my-bucket/In*/Ka*/Ban",
text: "my-bucket/India/Karnataka/Ban/Ban/Ban/Ban/Ban",
matched: true,
},
// Test case - 13.
// Test case to validate that `*` can be expanded into multiple prefixes.
{
pattern: "my-bucket/In*/Ka*/Ban",
text: "my-bucket/India/Karnataka/Area1/Area2/Area3/Ban",
matched: true,
},
// Test case - 14.
// Test case to validate that `*` can be expanded into multiple prefixes.
{
pattern: "my-bucket/In*/Ka*/Ban",
text: "my-bucket/India/State1/State2/Karnataka/Area1/Area2/Area3/Ban",
matched: true,
},
// Test case - 15.
// Test case where the keyname part of the pattern is expanded in the text.
{
pattern: "my-bucket/In*/Ka*/Ban",
text: "my-bucket/India/Karnataka/Bangalore",
matched: false,
},
// Test case - 16.
// Test case with prefixes and wildcard expanded for all "*".
{
pattern: "my-bucket/In*/Ka*/Ban*",
text: "my-bucket/India/Karnataka/Bangalore",
matched: true,
},
// Test case - 17.
// Test case with keyname part being a wildcard in the pattern.
{
pattern: "my-bucket/*",
text: "my-bucket/India",
matched: true,
},
// Test case - 18.
{
pattern: "my-bucket/oo*",
text: "my-bucket/odo",
matched: false,
},
// Test case - 19.
{
pattern: "my-bucket/oo?*",
text: "my-bucket/oo???",
matched: true,
},
// Test case - 20:
{
pattern: "my-bucket/oo??*",
text: "my-bucket/odo",
matched: false,
},
// Test case - 21:
{
pattern: "?h?*",
text: "?h?hello",
matched: true,
},
// Test case - 22:
{
pattern: "a?",
text: "a",
matched: true,
},
}
// Iterating over the test cases, call the function under test and assert the output.
b.Run("0-prefix-reference", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = strings.HasPrefix(testCases[0].text, "a")
}
})
for i, testCase := range testCases {
b.Run(fmt.Sprintf("bench-%d", i), func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = MatchSimple(testCase.pattern, testCase.text)
}
})
}
}

func TestMatchAsPatternPrefix(t *testing.T) {
testCases := []struct {
pattern string
Expand Down
Loading