Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: collections matchers should display type of expectation #408

Merged
merged 1 commit into from
Feb 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)))
})
})
})
})