-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
b643bc9
commit a9c3b11
Showing
6 changed files
with
934 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
module github.com/oxyno-zeta/gomock-extra-matcher | ||
|
||
go 1.15 | ||
|
||
require github.com/golang/mock v1.4.4 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= | ||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= | ||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | ||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | ||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
package extra | ||
|
||
import ( | ||
"fmt" | ||
"reflect" | ||
|
||
"github.com/golang/mock/gomock" | ||
) | ||
|
||
// MMatcher interface improved to add functions | ||
type MMatcher interface { | ||
gomock.Matcher | ||
// Add a matcher for a specific key | ||
Key(key interface{}, match interface{}) MMatcher | ||
} | ||
|
||
type mStorage struct { | ||
key interface{} | ||
match interface{} | ||
} | ||
|
||
type mapMatcher struct { | ||
keys []*mStorage | ||
} | ||
|
||
func (m *mapMatcher) String() string { | ||
str := "" | ||
|
||
// Loop over all keys | ||
for in, v := range m.keys { | ||
// Add separator for display | ||
if in > 0 { | ||
str += ", " | ||
} | ||
|
||
// Check if key is a gomock matcher | ||
m, ok := v.key.(gomock.Matcher) | ||
if ok { | ||
str += fmt.Sprintf("key %s", m.String()) | ||
} else { | ||
str += fmt.Sprintf("key %v", v.key) | ||
} | ||
|
||
// Try to cast to a matcher interface | ||
m, ok = v.match.(gomock.Matcher) | ||
// Check if cast is ok | ||
if ok { | ||
str += fmt.Sprintf(" must match %s", m.String()) | ||
} else { | ||
str += fmt.Sprintf(" must be equal to %v", v.match) | ||
} | ||
} | ||
|
||
return str | ||
} | ||
|
||
func (m *mapMatcher) Matches(x interface{}) bool { | ||
// Check if x is nil | ||
if x == nil { | ||
return false | ||
} | ||
|
||
// Value of interface input | ||
rval := reflect.ValueOf(x) | ||
rkind := rval.Kind() | ||
// Check if reflect value is supported or not | ||
if rkind != reflect.Map { | ||
return false | ||
} | ||
|
||
// Default case | ||
res := len(m.keys) != 0 | ||
|
||
// Create reflect indirect | ||
// indirect := reflect.Indirect(rval) | ||
// Loop over all matcher keys | ||
for _, kk := range m.keys { | ||
// Store if matcher key can be found | ||
matchKeyFound := false | ||
// Loop over map keys | ||
for _, kVal := range rval.MapKeys() { | ||
// Get key data | ||
keyD := kVal.Interface() | ||
// Get reflect value from key | ||
rv := rval.MapIndex(kVal) | ||
// Get data from key | ||
val := rv.Interface() | ||
// Check if matcher key is matching current key | ||
if !isMatchingData(kk.key, keyD) { | ||
// Skip this key | ||
continue | ||
} | ||
|
||
// Set match key as found | ||
matchKeyFound = true | ||
|
||
// Check map key value is matching | ||
res = res && isMatchingData(kk.match, val) | ||
|
||
// Break the loop at this step | ||
// No need to continue to check map values | ||
break | ||
} | ||
|
||
// Check if match key was found | ||
if !matchKeyFound { | ||
// Match key wasn't found, it is an error | ||
return false | ||
} | ||
|
||
// Check result | ||
if !res { | ||
// If result isn't true at this step, stop now | ||
return false | ||
} | ||
} | ||
|
||
return res | ||
} | ||
|
||
func isMatchingData(matchKey, keyData interface{}) bool { | ||
// Check if given key in matcher is a gomock matcher | ||
mk, ok := matchKey.(gomock.Matcher) | ||
if ok { | ||
return mk.Matches(keyData) | ||
} | ||
|
||
return matchKey == keyData | ||
} | ||
|
||
func (m *mapMatcher) Key(key interface{}, match interface{}) MMatcher { | ||
// Check if key exists | ||
if key == nil { | ||
return m | ||
} | ||
// Key name exists => add data | ||
m.keys = append(m.keys, &mStorage{key: key, match: match}) | ||
// Return | ||
return m | ||
} | ||
|
||
// MapMatcher will return a new map matcher | ||
func MapMatcher() MMatcher { return &mapMatcher{} } |
Oops, something went wrong.