Skip to content

Commit

Permalink
fix: collections matchers should display type of expectation (#408)
Browse files Browse the repository at this point in the history
  • Loading branch information
blgm committed Feb 1, 2021
1 parent 073b880 commit 6b4eb5a
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 6 deletions.
31 changes: 27 additions & 4 deletions matchers/consist_of.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,29 @@ func matchers(expectedElems []interface{}) (matchers []interface{}) {
return
}

func presentable(elems []interface{}) interface{} {
elems = flatten(elems)

if len(elems) == 0 {
return []interface{}{}
}

sv := reflect.ValueOf(elems)
tt := sv.Index(0).Elem().Type()
for i := 1; i < sv.Len(); i++ {
if sv.Index(i).Elem().Type() != tt {
return elems
}
}

ss := reflect.MakeSlice(reflect.SliceOf(tt), sv.Len(), sv.Len())
for i := 0; i < sv.Len(); i++ {
ss.Index(i).Set(sv.Index(i).Elem())
}

return ss.Interface()
}

func valuesOf(actual interface{}) []interface{} {
value := reflect.ValueOf(actual)
values := []interface{}{}
Expand All @@ -99,11 +122,11 @@ func valuesOf(actual interface{}) []interface{} {
}

func (matcher *ConsistOfMatcher) FailureMessage(actual interface{}) (message string) {
message = format.Message(actual, "to consist of", flatten(matcher.Elements))
message = format.Message(actual, "to consist of", presentable(matcher.Elements))
message = appendMissingElements(message, matcher.missingElements)
if len(matcher.extraElements) > 0 {
message = fmt.Sprintf("%s\nthe extra elements were\n%s", message,
format.Object(matcher.extraElements, 1))
format.Object(presentable(matcher.extraElements), 1))
}
return
}
Expand All @@ -113,9 +136,9 @@ func appendMissingElements(message string, missingElements []interface{}) string
return message
}
return fmt.Sprintf("%s\nthe missing elements were\n%s", message,
format.Object(missingElements, 1))
format.Object(presentable(missingElements), 1))
}

func (matcher *ConsistOfMatcher) NegatedFailureMessage(actual interface{}) (message string) {
return format.Message(actual, "not to consist of", flatten(matcher.Elements))
return format.Message(actual, "not to consist of", presentable(matcher.Elements))
}
50 changes: 50 additions & 0 deletions matchers/consist_of_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,5 +127,55 @@ var _ = Describe("ConsistOf", func() {
Expect(failures).To(ConsistOf(MatchRegexp(expected)))
})
})

When("the expected values are the same type", func() {
It("uses that type for the expectation slice", func() {
failures := InterceptGomegaFailures(func() {
Expect([]string{"A", "B"}).To(ConsistOf("A", "C"))
})

expected := `to consist of
\s*<\[\]string \| len:2, cap:2>: \["A", "C"\]
the missing elements were
\s*<\[\]string \| len:1, cap:1>: \["C"\]
the extra elements were
\s*<\[\]string \| len:1, cap:1>: \["B"\]`
Expect(failures).To(ConsistOf(MatchRegexp(expected)))
})

It("uses that type for the negated expectation slice", func() {
failures := InterceptGomegaFailures(func() {
Expect([]uint64{1, 2}).NotTo(ConsistOf(uint64(1), uint64(2)))
})

expected := `not to consist of\n\s*<\[\]uint64 \| len:2, cap:2>: \[1, 2\]`
Expect(failures).To(ConsistOf(MatchRegexp(expected)))
})
})

When("the expected values are different types", func() {
It("uses interface{} for the expectation slice", func() {
failures := InterceptGomegaFailures(func() {
Expect([]interface{}{1, true}).To(ConsistOf(1, "C"))
})

expected := `to consist of
\s*<\[\]interface {} \| len:2, cap:2>: \[1, "C"\]
the missing elements were
\s*<\[\]string \| len:1, cap:1>: \["C"\]
the extra elements were
\s*<\[\]bool \| len:1, cap:1>: \[true\]`
Expect(failures).To(ConsistOf(MatchRegexp(expected)))
})

It("uses interface{} for the negated expectation slice", func() {
failures := InterceptGomegaFailures(func() {
Expect([]interface{}{1, "B"}).NotTo(ConsistOf(1, "B"))
})

expected := `not to consist of\n\s*<\[\]interface {} \| len:2, cap:2>: \[1, "B"\]`
Expect(failures).To(ConsistOf(MatchRegexp(expected)))
})
})
})
})
4 changes: 2 additions & 2 deletions matchers/contain_elements_matcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ func (matcher *ContainElementsMatcher) Match(actual interface{}) (success bool,
}

func (matcher *ContainElementsMatcher) FailureMessage(actual interface{}) (message string) {
message = format.Message(actual, "to contain elements", flatten(matcher.Elements))
message = format.Message(actual, "to contain elements", presentable(matcher.Elements))
return appendMissingElements(message, matcher.missingElements)
}

func (matcher *ContainElementsMatcher) NegatedFailureMessage(actual interface{}) (message string) {
return format.Message(actual, "not to contain elements", flatten(matcher.Elements))
return format.Message(actual, "not to contain elements", presentable(matcher.Elements))
}
46 changes: 46 additions & 0 deletions matchers/contain_elements_matcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,5 +102,51 @@ var _ = Describe("ContainElements", func() {
Expect(failures).To(ConsistOf(MatchRegexp(expected)))
})
})

When("the expected values are the same type", func() {
It("uses that type for the expectation slice", func() {
failures := InterceptGomegaFailures(func() {
Expect([]string{"A", "B"}).To(ContainElements("A", "B", "C"))
})

expected := `to contain elements
\s*<\[\]string \| len:3, cap:3>: \["A", "B", "C"\]
the missing elements were
\s*<\[\]string \| len:1, cap:1>: \["C"\]`
Expect(failures).To(ConsistOf(MatchRegexp(expected)))
})

It("uses that type for the negated expectation slice", func() {
failures := InterceptGomegaFailures(func() {
Expect([]uint64{1, 2}).NotTo(ContainElements(uint64(1), uint64(2)))
})

expected := `not to contain elements\n\s*<\[\]uint64 \| len:2, cap:2>: \[1, 2\]`
Expect(failures).To(ConsistOf(MatchRegexp(expected)))
})
})

When("the expected values are different types", func() {
It("uses interface{} for the expectation slice", func() {
failures := InterceptGomegaFailures(func() {
Expect([]interface{}{1, true}).To(ContainElements(1, "C"))
})

expected := `to contain elements
\s*<\[\]interface {} \| len:2, cap:2>: \[1, "C"\]
the missing elements were
\s*<\[\]string \| len:1, cap:1>: \["C"\]`
Expect(failures).To(ConsistOf(MatchRegexp(expected)))
})

It("uses interface{} for the negated expectation slice", func() {
failures := InterceptGomegaFailures(func() {
Expect([]interface{}{1, "B"}).NotTo(ContainElements(1, "B"))
})

expected := `not to contain elements\n\s*<\[\]interface {} \| len:2, cap:2>: \[1, "B"\]`
Expect(failures).To(ConsistOf(MatchRegexp(expected)))
})
})
})
})

0 comments on commit 6b4eb5a

Please sign in to comment.