Add BeIdenticalTo matcher This aims to address issue #104. This should be quite similar to the BeSameInstanceAs matcher from Cedar, one of my personal favorites. Internally it uses the == operator, and should positively match primitive values as well as identical pointers to a value..
diff --git a/matchers.go b/matchers.go index afb7720..12d2b96 100644 --- a/matchers.go +++ b/matchers.go
@@ -26,6 +26,15 @@ } } +//BeIdenticalTo uses the == operator to compare actual with expected. +//BeIdenticalTo is strict about types when performing comparisons. +//It is an error for both actual and expected to be nil. Use BeNil() instead. +func BeIdenticalTo(expected interface{}) types.GomegaMatcher { + return &matchers.BeIdenticalToMatcher{ + Expected: expected, + } +} + //BeNil succeeds if actual is nil func BeNil() types.GomegaMatcher { return &matchers.BeNilMatcher{}
diff --git a/matchers/be_identical_to.go b/matchers/be_identical_to.go new file mode 100644 index 0000000..fdcda4d --- /dev/null +++ b/matchers/be_identical_to.go
@@ -0,0 +1,37 @@ +package matchers + +import ( + "fmt" + "runtime" + + "github.com/onsi/gomega/format" +) + +type BeIdenticalToMatcher struct { + Expected interface{} +} + +func (matcher *BeIdenticalToMatcher) Match(actual interface{}) (success bool, matchErr error) { + if actual == nil && matcher.Expected == nil { + return false, fmt.Errorf("Refusing to compare <nil> to <nil>.\nBe explicit and use BeNil() instead. This is to avoid mistakes where both sides of an assertion are erroneously uninitialized.") + } + + defer func() { + if r := recover(); r != nil { + if _, ok := r.(runtime.Error); ok { + success = false + matchErr = nil + } + } + }() + + return actual == matcher.Expected, nil +} + +func (matcher *BeIdenticalToMatcher) FailureMessage(actual interface{}) string { + return format.Message(actual, "to be identical to", matcher.Expected) +} + +func (matcher *BeIdenticalToMatcher) NegatedFailureMessage(actual interface{}) string { + return format.Message(actual, "not to be identical to", matcher.Expected) +}
diff --git a/matchers/be_identical_to_test.go b/matchers/be_identical_to_test.go new file mode 100644 index 0000000..8b90a1a --- /dev/null +++ b/matchers/be_identical_to_test.go
@@ -0,0 +1,61 @@ +package matchers_test + +import ( + "errors" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/matchers" +) + +var _ = Describe("BeIdenticalTo", func() { + Context("when asserting that nil equals nil", func() { + It("should error", func() { + success, err := (&BeIdenticalToMatcher{Expected: nil}).Match(nil) + + Ω(success).Should(BeFalse()) + Ω(err).Should(HaveOccurred()) + }) + }) + + It("should treat the same pointer to a struct as identical", func() { + mySpecialStruct := myCustomType{} + Ω(&mySpecialStruct).Should(BeIdenticalTo(&mySpecialStruct)) + Ω(&myCustomType{}).ShouldNot(BeIdenticalTo(&mySpecialStruct)) + }) + + It("should be strict about types", func() { + Ω(5).ShouldNot(BeIdenticalTo("5")) + Ω(5).ShouldNot(BeIdenticalTo(5.0)) + Ω(5).ShouldNot(BeIdenticalTo(3)) + }) + + It("should treat primtives as identical", func() { + Ω("5").Should(BeIdenticalTo("5")) + Ω("5").ShouldNot(BeIdenticalTo("55")) + + Ω(5.55).Should(BeIdenticalTo(5.55)) + Ω(5.55).ShouldNot(BeIdenticalTo(6.66)) + + Ω(5).Should(BeIdenticalTo(5)) + Ω(5).ShouldNot(BeIdenticalTo(55)) + }) + + It("should treat the same pointers to a slice as identical", func() { + mySlice := []int{1, 2} + Ω(&mySlice).Should(BeIdenticalTo(&mySlice)) + Ω(&mySlice).ShouldNot(BeIdenticalTo(&[]int{1, 2})) + }) + + It("should treat the same pointers to a map as identical", func() { + myMap := map[string]string{"a": "b", "c": "d"} + Ω(&myMap).Should(BeIdenticalTo(&myMap)) + Ω(myMap).ShouldNot(BeIdenticalTo(map[string]string{"a": "b", "c": "d"})) + }) + + It("should treat the same pointers to an error as identical", func() { + myError := errors.New("foo") + Ω(&myError).Should(BeIdenticalTo(&myError)) + Ω(errors.New("foo")).ShouldNot(BeIdenticalTo(errors.New("bar"))) + }) +})