Skip to content

Commit

Permalink
add more matchers (#70)
Browse files Browse the repository at this point in the history
  • Loading branch information
ovechkin-dm authored Jun 12, 2024
1 parent d35d955 commit d1d7bbc
Show file tree
Hide file tree
Showing 2 changed files with 331 additions and 0 deletions.
161 changes: 161 additions & 0 deletions mock/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"reflect"
"regexp"
"strings"

"github.com/ovechkin-dm/mockio/config"
Expand Down Expand Up @@ -112,6 +113,166 @@ func AnyOfType[T any](t T) T {
return Any[T]()
}

// Nil returns matcher that matches nil argument.
// Example usage:
//
// WhenSingle(myMock.MyMethod(Nil[string]())).ThenReturn("bar")
func Nil[T any]() T {
m := registry.FunMatcher[T]("Nil", func(m []any, actual T) bool {
var d any = actual
return d == nil
})
registry.AddMatcher(m)
var t T
return t
}

// NotNil returns matcher that matches non-nil argument.
// Example usage:
//
// WhenSingle(myMock.MyMethod(NotNil[string]())).ThenReturn("bar")
func NotNil[T any]() T {
m := registry.FunMatcher[T]("NotNil", func(m []any, actual T) bool {
var d any = actual
return d != nil
})
registry.AddMatcher(m)
var t T
return t
}

// Regex returns matcher that matches string against provided pattern.
// Example usage:
//
// WhenSingle(myMock.MyMethod(Regex[string]("foo"))).ThenReturn("bar")
func Regex(pattern string) string {
re, err := regexp.Compile(pattern)
desc := fmt.Sprintf("Regex(%v)", pattern)
if err != nil {
desc = fmt.Sprintf("InvalidRegex(%v)", pattern)
}
m := registry.FunMatcher(desc, func(m []any, actual string) bool {
return err == nil && re.MatchString(actual)
})
registry.AddMatcher(m)
return ""
}

// Substring returns matcher that matches any string that contains specified substring.
// Example usage:
//
// WhenSingle(myMock.MyMethod(Substring("foo"))).ThenReturn("bar")
func Substring(value string) string {
desc := fmt.Sprintf("Substring(%v)", value)
m := registry.FunMatcher(desc, func(m []any, actual string) bool {
return strings.Contains(actual, value)
})
registry.AddMatcher(m)
return ""
}

// SliceLen returns matcher that matches any slice of length n.
// Example usage:
//
// WhenSingle(myMock.MyMethod(SliceLen(10))).ThenReturn("bar")
func SliceLen[T any](value int) []T {
desc := fmt.Sprintf("SliceLen(%v)", value)
m := registry.FunMatcher(desc, func(m []any, actual []T) bool {
return len(actual) == value
})
registry.AddMatcher(m)
var t []T
return t
}

// MapLen returns matcher that matches any map of length n.
// Example usage:
//
// WhenSingle(myMock.MyMethod(MapLen(10))).ThenReturn("bar")
func MapLen[K comparable, V any](value int) map[K]V {
desc := fmt.Sprintf("MapLen(%v)", value)
m := registry.FunMatcher(desc, func(m []any, actual map[K]V) bool {
return len(actual) == value
})
registry.AddMatcher(m)
var t map[K]V
return t
}

// SliceContains returns matcher that matches any slice that contains specified values.
// Example usage:
//
// WhenSingle(myMock.MyMethod(SliceContains("foo", "bar"))).ThenReturn("baz")
func SliceContains[T any](values ...T) []T {
desc := fmt.Sprintf("SliceContains(%v)", values)
m := registry.FunMatcher(desc, func(m []any, actual []T) bool {
amap := make(map[any]struct{})
for _, v := range actual {
amap[v] = struct{}{}
}
for _, v := range values {
_, ok := amap[v]
if !ok {
return false
}
}
return true
})
registry.AddMatcher(m)
var t []T
return t
}

// MapContains returns matcher that matches any map that contains specified keys.
// Example usage:
//
// WhenSingle(myMock.MyMethod(MapContains("foo", "bar"))).ThenReturn("baz")
func MapContains[K comparable, V any](values ...K) map[K]V {
desc := fmt.Sprintf("MapContains(%v)", values)
m := registry.FunMatcher(desc, func(m []any, actual map[K]V) bool {
for _, v := range values {
_, ok := actual[v]
if !ok {
return false
}
}
return true
})
registry.AddMatcher(m)
var t map[K]V
return t
}

// SliceEqualUnordered returns matcher that matches slice with same values without taking order of elements into account.
// Example usage:
//
// WhenSingle(myMock.MyMethod(SliceEqualUnordered([]int{2,1}))).ThenReturn("baz")
func SliceEqualUnordered[T any](values []T) []T {
desc := fmt.Sprintf("EqualUnordered(%v)", values)
vmap := make(map[any]struct{})
for _, v := range values {
vmap[v] = struct{}{}
}
m := registry.FunMatcher(desc, func(m []any, actual []T) bool {
if len(vmap) != len(values) {
return false
}
if len(actual) != len(values) {
return false
}
for _, v := range actual {
_, ok := vmap[v]
if !ok {
return false
}
}
return true
})
registry.AddMatcher(m)
var t []T
return t
}

// Exact returns a matcher that matches values of type T that are equal to the provided value.
// The value passed to Exact must be comparable with values of type T.
//
Expand Down
170 changes: 170 additions & 0 deletions tests/match/match_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ type MyInterface interface {
Test(m *MyStruct) int
}

type SliceInterface interface {
Test(m []int) int
}

type MapInterface interface {
Test(m map[int]int) int
}

func TestAny(t *testing.T) {
r := common.NewMockReporter(t)
SetUp(r)
Expand Down Expand Up @@ -142,6 +150,168 @@ func TestDeepEqual(t *testing.T) {
r.AssertEqual(result, 9)
}

func TestNilMatch(t *testing.T) {
r := common.NewMockReporter(t)
SetUp(r)
m := Mock[Iface]()
WhenSingle(m.Test(Nil[any]())).ThenReturn(true)
ret := m.Test(nil)
r.AssertEqual(true, ret)
}

func TestNilNoMatch(t *testing.T) {
r := common.NewMockReporter(t)
SetUp(r)
m := Mock[Iface]()
WhenSingle(m.Test(Nil[any]())).ThenReturn(true)
ret := m.Test(10)
r.AssertEqual(false, ret)
}

func TestSubstringMatch(t *testing.T) {
r := common.NewMockReporter(t)
SetUp(r)
m := Mock[Iface]()
WhenSingle(m.Test(Substring("test"))).ThenReturn(true)
ret := m.Test("123test123")
r.AssertEqual(true, ret)
}

func TestSubstringNoMatch(t *testing.T) {
r := common.NewMockReporter(t)
SetUp(r)
m := Mock[Iface]()
WhenSingle(m.Test(Substring("test321"))).ThenReturn(true)
ret := m.Test("123test123")
r.AssertEqual(false, ret)
}

func TestNotNilMatch(t *testing.T) {
r := common.NewMockReporter(t)
SetUp(r)
m := Mock[Iface]()
WhenSingle(m.Test(NotNil[any]())).ThenReturn(true)
ret := m.Test(10)
r.AssertEqual(true, ret)
}

func TestNotNilNoMatch(t *testing.T) {
r := common.NewMockReporter(t)
SetUp(r)
m := Mock[Iface]()
WhenSingle(m.Test(NotNil[any]())).ThenReturn(true)
ret := m.Test(nil)
r.AssertEqual(false, ret)
}

func TestRegexMatch(t *testing.T) {
r := common.NewMockReporter(t)
SetUp(r)
m := Mock[Iface]()
WhenSingle(m.Test(Regex("test"))).ThenReturn(true)
ret := m.Test("123test123")
r.AssertEqual(true, ret)
}

func TestRegexNoMatch(t *testing.T) {
r := common.NewMockReporter(t)
SetUp(r)
m := Mock[Iface]()
WhenSingle(m.Test(Regex("test321"))).ThenReturn(true)
ret := m.Test("123test123")
r.AssertEqual(false, ret)
}

func TestSliceLenMatch(t *testing.T) {
r := common.NewMockReporter(t)
SetUp(r)
m := Mock[SliceInterface]()
WhenSingle(m.Test(SliceLen[int](3))).ThenReturn(3)
ret := m.Test([]int{1, 2, 3})
r.AssertEqual(3, ret)
}

func TestSliceLenNoMatch(t *testing.T) {
r := common.NewMockReporter(t)
SetUp(r)
m := Mock[SliceInterface]()
WhenSingle(m.Test(SliceLen[int](4))).ThenReturn(3)
ret := m.Test([]int{1, 2, 3})
r.AssertEqual(0, ret)
}

func TestMapLenMatch(t *testing.T) {
r := common.NewMockReporter(t)
SetUp(r)
m := Mock[MapInterface]()
WhenSingle(m.Test(MapLen[int, int](3))).ThenReturn(3)
ret := m.Test(map[int]int{1: 1, 2: 2, 3: 3})
r.AssertEqual(3, ret)
}

func TestMapLenNoMatch(t *testing.T) {
r := common.NewMockReporter(t)
SetUp(r)
m := Mock[MapInterface]()
WhenSingle(m.Test(MapLen[int, int](3))).ThenReturn(3)
ret := m.Test(map[int]int{1: 1, 2: 2, 3: 3, 4: 4})
r.AssertEqual(0, ret)
}

func TestSliceContainsMatch(t *testing.T) {
r := common.NewMockReporter(t)
SetUp(r)
m := Mock[SliceInterface]()
WhenSingle(m.Test(SliceContains[int](3))).ThenReturn(3)
ret := m.Test([]int{1, 2, 3})
r.AssertEqual(3, ret)
}

func TestSliceContainsNoMatch(t *testing.T) {
r := common.NewMockReporter(t)
SetUp(r)
m := Mock[SliceInterface]()
WhenSingle(m.Test(SliceContains[int](4))).ThenReturn(3)
ret := m.Test([]int{1, 2, 3})
r.AssertEqual(0, ret)
}

func TestMapContainsMatch(t *testing.T) {
r := common.NewMockReporter(t)
SetUp(r)
m := Mock[MapInterface]()
WhenSingle(m.Test(MapContains[int, int](3))).ThenReturn(3)
ret := m.Test(map[int]int{1: 1, 2: 2, 3: 3})
r.AssertEqual(3, ret)
}

func TestMapContainsNoMatch(t *testing.T) {
r := common.NewMockReporter(t)
SetUp(r)
m := Mock[MapInterface]()
WhenSingle(m.Test(MapContains[int, int](4))).ThenReturn(3)
ret := m.Test(map[int]int{1: 1, 2: 2, 3: 3})
r.AssertEqual(0, ret)
}

func TestSliceEqualUnorderedMatch(t *testing.T) {
r := common.NewMockReporter(t)
SetUp(r)
m := Mock[SliceInterface]()
WhenSingle(m.Test(SliceEqualUnordered[int]([]int{1, 2, 3}))).ThenReturn(3)
ret := m.Test([]int{3, 2, 1})
r.AssertEqual(3, ret)
}

func TestSliceEqualUnorderedNoMatch(t *testing.T) {
r := common.NewMockReporter(t)
SetUp(r)
m := Mock[SliceInterface]()
WhenSingle(m.Test(SliceEqualUnordered[int]([]int{1, 2, 3}))).ThenReturn(3)
ret := m.Test([]int{3, 2, 1, 4})
r.AssertEqual(0, ret)
}

func TestUnexpectedUseOfMatchers(t *testing.T) {
r := common.NewMockReporter(t)
SetUp(r)
Expand Down

0 comments on commit d1d7bbc

Please sign in to comment.