Skip to content
This repository was archived by the owner on Feb 17, 2025. It is now read-only.

Commit dbf04ff

Browse files
committed
Add map Contains and NotContains
1 parent 1198f4d commit dbf04ff

File tree

3 files changed

+72
-3
lines changed

3 files changed

+72
-3
lines changed

map.go

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
package verify
22

3-
import "fmt"
3+
import (
4+
"fmt"
5+
6+
"github.com/google/go-cmp/cmp"
7+
)
48

59
// FluentMap encapsulates assertions for a map.
610
type FluentMap[K comparable, V any] struct {
@@ -28,6 +32,40 @@ func (x FluentMap[K, V]) NotEmpty() FailureMessage {
2832
return FailureMessage(fmt.Sprintf("an empty map\ngot: %+v", x.Got))
2933
}
3034

35+
// Contain tests if the map contains all pairs from want.
36+
func (x FluentMap[K, V]) Contain(want map[K]V, opts ...cmp.Option) FailureMessage {
37+
missing := x.miss(want, opts)
38+
if len(missing) == 0 {
39+
return ""
40+
}
41+
return FailureMessage(fmt.Sprintf("not contains all pairs\ngot: %+v\nwant: %+v\nmissing: %+v", x.Got, want, missing))
42+
}
43+
44+
// NotContain tests if the slice does not have the same element as want in any order.
45+
func (x FluentMap[K, V]) NotContain(want map[K]V, opts ...cmp.Option) FailureMessage {
46+
missing := x.miss(want, opts)
47+
if len(missing) > 0 {
48+
return ""
49+
}
50+
return FailureMessage(fmt.Sprintf("contains all pairs\ngot: %+v\nwant: %+v", x.Got, want))
51+
}
52+
53+
func (x FluentMap[K, V]) miss(want map[K]V, opts []cmp.Option) map[K]V {
54+
missing := map[K]V{}
55+
for k, v := range want {
56+
got, ok := x.Got[k]
57+
if !ok {
58+
missing[k] = v
59+
continue
60+
}
61+
if !cmp.Equal(v, got, opts...) {
62+
missing[k] = v
63+
continue
64+
}
65+
}
66+
return missing
67+
}
68+
3169
// TODO: Contain(elements map[K]V) FailureMessage
3270

3371
// TODO: NotContain(elements map[K]V) FailureMessage

map_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ func TestMap(t *testing.T) {
2525
"a": {Str: "text", Bool: true, Slice: []int{1, 2, 3}},
2626
"b": {Slice: []int{9, 8, 7}},
2727
}
28+
has := map[string]A{
29+
"a": {Str: "text", Bool: true, Slice: []int{1, 2, 3}},
30+
}
31+
notHas := map[string]A{
32+
"a": {Str: "text", Bool: true, Slice: []int{1, 2, 3}},
33+
"b": {Slice: []int{1, 4, 7}},
34+
"c": {Slice: []int{9, 8, 7}},
35+
}
2836
t.Run("Empty", func(t *testing.T) {
2937
t.Run("Passed", func(t *testing.T) {
3038
got := verify.Map(map[string]A{}).Empty()
@@ -45,4 +53,25 @@ func TestMap(t *testing.T) {
4553
assertFailed(t, got, "an empty map")
4654
})
4755
})
56+
57+
t.Run("Contain", func(t *testing.T) {
58+
t.Run("Passed", func(t *testing.T) {
59+
got := verify.Map(dict).Contain(has)
60+
assertPassed(t, got)
61+
})
62+
t.Run("Failed", func(t *testing.T) {
63+
got := verify.Map(dict).Contain(notHas)
64+
assertFailed(t, got, "not contains all pairs")
65+
})
66+
})
67+
t.Run("NotContain", func(t *testing.T) {
68+
t.Run("Passed", func(t *testing.T) {
69+
got := verify.Map(dict).NotContain(notHas)
70+
assertPassed(t, got)
71+
})
72+
t.Run("Failed", func(t *testing.T) {
73+
got := verify.Map(dict).NotContain(has)
74+
assertFailed(t, got, "contains all pairs")
75+
})
76+
})
4877
}

slice.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ func (x FluentSlice[T]) NotEmpty() FailureMessage {
3232
return FailureMessage(fmt.Sprintf("an empty slice\ngot: %+v", x.Got))
3333
}
3434

35-
// Equivalent tests if the slice has the same element as want in any order.
35+
// Equivalent tests if the slice has the same items as want in any order.
3636
func (x FluentSlice[T]) Equivalent(want []T, opts ...cmp.Option) FailureMessage {
3737
extraGot, extraWant := x.diff(want, opts)
3838
if len(extraGot) == 0 && len(extraWant) == 0 {
@@ -41,7 +41,7 @@ func (x FluentSlice[T]) Equivalent(want []T, opts ...cmp.Option) FailureMessage
4141
return FailureMessage(fmt.Sprintf("not equivalent\nextra got: %+v\nextra want: %+v", extraGot, extraWant))
4242
}
4343

44-
// NotEquivalent tests if the slice does not have the same element as want in any order.
44+
// NotEquivalent tests if the slice does not have the same items as want in any order.
4545
func (x FluentSlice[T]) NotEquivalent(want []T, opts ...cmp.Option) FailureMessage {
4646
extraGot, extraWant := x.diff(want, opts)
4747
if len(extraGot) != 0 || len(extraWant) != 0 {
@@ -83,6 +83,7 @@ func (x FluentSlice[T]) diff(want []T, opts []cmp.Option) (extraGot, extraWant [
8383
return
8484
}
8585

86+
// TODO: Rename to ContainItem and add Contain
8687
// Contain tests if the slice contains the item.
8788
func (x FluentSlice[T]) Contain(item T, opts ...cmp.Option) FailureMessage {
8889
for _, v := range x.Got {
@@ -93,6 +94,7 @@ func (x FluentSlice[T]) Contain(item T, opts ...cmp.Option) FailureMessage {
9394
return FailureMessage(fmt.Sprintf("slice does not contain the item\ngot: %+v\nitem: %+v", x.Got, item))
9495
}
9596

97+
// TODO: Rename to NotContainItem and add NotContain
9698
// NotContain tests if the slice does not contain the item.
9799
func (x FluentSlice[T]) NotContain(item T, opts ...cmp.Option) FailureMessage {
98100
for _, v := range x.Got {

0 commit comments

Comments
 (0)