Skip to content

Commit

Permalink
feat: add Regex matcher for strings
Browse files Browse the repository at this point in the history
  • Loading branch information
merrett010 committed Oct 16, 2023
1 parent 892b665 commit 9ec4913
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 0 deletions.
32 changes: 32 additions & 0 deletions gomock/matchers.go
Expand Up @@ -17,6 +17,7 @@ package gomock
import (
"fmt"
"reflect"
"regexp"
"strings"
)

Expand Down Expand Up @@ -168,6 +169,26 @@ func (n notMatcher) String() string {
return "not(" + n.m.String() + ")"
}

type regexMatcher struct {
regex string
}

func (m regexMatcher) Matches(x any) bool {
str, ok := x.(string)
if !ok {
return false
}
match, err := regexp.MatchString(m.regex, str)
if !match || err != nil {
return false
}
return true
}

func (m regexMatcher) String() string {
return "matching regex " + m.regex
}

type assignableToTypeOfMatcher struct {
targetType reflect.Type
}
Expand Down Expand Up @@ -382,6 +403,17 @@ func Not(x any) Matcher {
return notMatcher{Eq(x)}
}

// Regex checks whether a string parameter matches the associated regex.
//
// Example usage:
//
// Regex("[0-9]{2}:[0-9]{2}").Matches("23:02") // returns true
// Regex("[0-9]{2}:[0-9]{2}").Matches("hello world") // returns false
// Regex("[0-9]{2}").Matches(21) // returns false as it's not a string
func Regex(regexStr string) Matcher {
return regexMatcher{regex: regexStr}
}

// AssignableToTypeOf is a Matcher that matches if the parameter to the mock
// function is assignable to the type of the parameter to this function.
//
Expand Down
47 changes: 47 additions & 0 deletions gomock/matchers_test.go
Expand Up @@ -47,6 +47,7 @@ func TestMatchers(t *testing.T) {
[]e{nil, (error)(nil), (chan bool)(nil), (*int)(nil)},
[]e{"", 0, make(chan bool), errors.New("err"), new(int)}},
{"test Not", gomock.Not(gomock.Eq(4)), []e{3, "blah", nil, int64(4)}, []e{4}},
{"test Regex", gomock.Regex("[0-9]{2}:[0-9]{2}"), []e{"23:02", "[23:02]: Hello world"}, []e{4, "23-02", "hello world", true}},
{"test All", gomock.All(gomock.Any(), gomock.Eq(4)), []e{4}, []e{3, "blah", nil, int64(4)}},
{"test Len", gomock.Len(2),
[]e{[]int{1, 2}, "ab", map[string]int{"a": 0, "b": 1}, [2]string{"a", "b"}},
Expand Down Expand Up @@ -92,6 +93,52 @@ func TestNotMatcher(t *testing.T) {
}
}

// A more thorough test of regexMatcher
func TestRegexMatcher(t *testing.T) {
tests := []struct {
name string
regex string
input any
wantMatch bool
wantStringResponse string
}{
{
name: "match for whole num regex with start and end position matching",
regex: "^\\d+$",
input: "2302",
wantMatch: true,
wantStringResponse: "matching regex ^\\d+$",
},
{
name: "match for valid regex with start and end position matching on longer string",
regex: "^[0-9]{2}:[0-9]{2}$",
input: "[23:02]: Hello world",
wantMatch: false,
wantStringResponse: "matching regex ^[0-9]{2}:[0-9]{2}$",
},
{
name: "match for invalid regex",
regex: "^[0-9{2}:[0-9]{2}$",
input: "23:02",
wantMatch: false,
wantStringResponse: "matching regex ^[0-9{2}:[0-9]{2}$",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
matcher := gomock.Regex(tt.regex)

if got := matcher.Matches(tt.input); got != tt.wantMatch {
t.Errorf("got = %v, wantMatch = %v", got, tt.wantMatch)
}
if gotStr := matcher.String(); gotStr != tt.wantStringResponse {
t.Errorf("got string = %v, want string = %v", gotStr, tt.wantStringResponse)
}
})
}
}

type Dog struct {
Breed, Name string
}
Expand Down

0 comments on commit 9ec4913

Please sign in to comment.