From 6af5403a1a7522a18c4ad6602b7b3d91c142dfef Mon Sep 17 00:00:00 2001 From: tank Date: Sat, 23 Apr 2022 11:46:19 +0800 Subject: [PATCH 1/3] feat: add CompareEqual using go-cmp --- go.mod | 2 + go.sum | 6 +- matchers.go | 10 +++ matchers/compare_matcher.go | 37 +++++++++ matchers/compare_matcher_test.go | 136 +++++++++++++++++++++++++++++++ 5 files changed, 189 insertions(+), 2 deletions(-) create mode 100644 matchers/compare_matcher.go create mode 100644 matchers/compare_matcher_test.go diff --git a/go.mod b/go.mod index 94cc3229c..fbb2e4a94 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.18 require ( github.com/golang/protobuf v1.5.2 + github.com/google/go-cmp v0.5.7 github.com/onsi/ginkgo/v2 v2.1.4 golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 gopkg.in/yaml.v2 v2.4.0 @@ -12,5 +13,6 @@ require ( require ( golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 // indirect golang.org/x/text v0.3.7 // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect google.golang.org/protobuf v1.28.0 // indirect ) diff --git a/go.sum b/go.sum index 2193bc027..de1d4a61b 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,9 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/onsi/ginkgo/v2 v2.1.4 h1:GNapqRSid3zijZ9H77KrgVG4/8KqiyRsxcSxe+7ApXY= github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 h1:HVyaeDAYux4pnY+D/SiwmLOR36ewZ4iGQIIrtnuCjFA= @@ -11,8 +12,9 @@ golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 h1:xHms4gcpe1YE7A3yIllJXP16C golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= diff --git a/matchers.go b/matchers.go index b58dd67cb..6a17bbddc 100644 --- a/matchers.go +++ b/matchers.go @@ -3,6 +3,7 @@ package gomega import ( "time" + "github.com/google/go-cmp/cmp" "github.com/onsi/gomega/matchers" "github.com/onsi/gomega/types" ) @@ -26,6 +27,15 @@ func BeEquivalentTo(expected interface{}) types.GomegaMatcher { } } +//Compare uses gocmp.Equal to compare. You can pass cmp.Option as options. +//It is an error for actual and expected to be nil. Use BeNil() instead. +func Compare(expected interface{}, opts ...cmp.Option) types.GomegaMatcher { + return &matchers.CompareMatcher{ + Expected: expected, + Options: opts, + } +} + //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. diff --git a/matchers/compare_matcher.go b/matchers/compare_matcher.go new file mode 100644 index 000000000..645f36290 --- /dev/null +++ b/matchers/compare_matcher.go @@ -0,0 +1,37 @@ +package matchers + +import ( + "bytes" + "fmt" + "github.com/google/go-cmp/cmp" + "github.com/onsi/gomega/format" +) + +type CompareMatcher struct { + Expected interface{} + Options cmp.Options +} + +func (matcher *CompareMatcher) Match(actual interface{}) (success bool, err error) { + if actual == nil && matcher.Expected == nil { + return false, fmt.Errorf("Refusing to compare to .\nBe explicit and use BeNil() instead. This is to avoid mistakes where both sides of an assertion are erroneously uninitialized.") + } + // Shortcut for byte slices. + // Comparing long byte slices with reflect.DeepEqual is very slow, + // so use bytes.Equal if actual and expected are both byte slices. + if actualByteSlice, ok := actual.([]byte); ok { + if expectedByteSlice, ok := matcher.Expected.([]byte); ok { + return bytes.Equal(actualByteSlice, expectedByteSlice), nil + } + } + + return cmp.Equal(actual, matcher.Expected, matcher.Options...), nil +} + +func (matcher *CompareMatcher) FailureMessage(actual interface{}) (message string) { + return cmp.Diff(matcher.Expected, actual) +} + +func (matcher *CompareMatcher) NegatedFailureMessage(actual interface{}) (message string) { + return format.Message(actual, "not to equal", matcher.Expected) +} diff --git a/matchers/compare_matcher_test.go b/matchers/compare_matcher_test.go new file mode 100644 index 000000000..8acbd0b36 --- /dev/null +++ b/matchers/compare_matcher_test.go @@ -0,0 +1,136 @@ +package matchers_test + +import ( + "errors" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/matchers" +) + +type wrapError struct { + msg string + err error +} + +func (e wrapError) Error() string { + return e.msg +} + +func (e wrapError) Unwrap() error { + return e.err +} + +var _ = Describe("Compare", func() { + When("asserting that nil compare equal nil", func() { + It("should error", func() { + success, err := (&CompareMatcher{Expected: nil}).Match(nil) + + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + }) + + Context("When asserting on nil", func() { + It("should do the right thing", func() { + Expect("foo").ShouldNot(Compare(nil)) + Expect(nil).ShouldNot(Compare(3)) + Expect([]int{1, 2}).ShouldNot(Compare(nil)) + }) + }) + + Context("When asserting time with different location ", func() { + var t1, t2 time.Time + + BeforeEach(func() { + t1 = time.Time{} + t2 = time.Time{}.Local() + }) + + It("should do the right thing", func() { + Expect(t1).ShouldNot(Equal(t2)) + Expect(t1).Should(Compare(t2)) + }) + }) + + Context("When struct contain unexported fields", func() { + type structWithUnexportedFields struct { + unexported string + Exported string + } + + var s1, s2 structWithUnexportedFields + + BeforeEach(func() { + s1 = structWithUnexportedFields{unexported: "unexported", Exported: "Exported"} + s2 = structWithUnexportedFields{unexported: "unexported", Exported: "Exported"} + }) + + It("should panic with unexported field", func() { + defer func() { + if e := recover(); e != nil { + Expect(e).Should(HavePrefix("cannot handle unexported field at")) + } + }() + + matcher := &CompareMatcher{ + Expected: s1, + } + _, _ = matcher.Match(s2) + }) + + It("should do the right thing", func() { + Expect(s1).Should(Compare(s2, cmpopts.IgnoreUnexported(structWithUnexportedFields{}))) + }) + }) + + Context("When compare error", func() { + var err1, err2 error + + It("not equal", func() { + err1 = errors.New("error") + err2 = errors.New("error") + Expect(err1).ShouldNot(Compare(err2, cmpopts.EquateErrors())) + }) + + It("equal if err1 is err2", func() { + err1 = errors.New("error") + err2 = &wrapError{ + msg: "some error", + err: err1, + } + + Expect(err1).Should(Compare(err2, cmpopts.EquateErrors())) + }) + }) + + Context("When asserting equal between objects", func() { + It("should do the right thing", func() { + Expect(5).Should(Compare(5)) + Expect(5.0).Should(Compare(5.0)) + + Expect(5).ShouldNot(Compare("5")) + Expect(5).ShouldNot(Compare(5.0)) + Expect(5).ShouldNot(Compare(3)) + + Expect("5").Should(Compare("5")) + Expect([]int{1, 2}).Should(Compare([]int{1, 2})) + Expect([]int{1, 2}).ShouldNot(Compare([]int{2, 1})) + Expect([]byte{'f', 'o', 'o'}).Should(Compare([]byte{'f', 'o', 'o'})) + Expect([]byte{'f', 'o', 'o'}).ShouldNot(Compare([]byte{'b', 'a', 'r'})) + Expect(map[string]string{"a": "b", "c": "d"}).Should(Compare(map[string]string{"a": "b", "c": "d"})) + Expect(map[string]string{"a": "b", "c": "d"}).ShouldNot(Compare(map[string]string{"a": "b", "c": "e"})) + + Expect(myCustomType{s: "abc", n: 3, f: 2.0, arr: []string{"a", "b"}}).Should(Compare(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}, cmpopts.IgnoreUnexported(myCustomType{}))) + + Expect(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).Should(Compare(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}, cmp.AllowUnexported(myCustomType{}))) + Expect(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).ShouldNot(Compare(myCustomType{s: "bar", n: 3, f: 2.0, arr: []string{"a", "b"}}, cmp.AllowUnexported(myCustomType{}))) + Expect(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).ShouldNot(Compare(myCustomType{s: "foo", n: 2, f: 2.0, arr: []string{"a", "b"}}, cmp.AllowUnexported(myCustomType{}))) + Expect(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).ShouldNot(Compare(myCustomType{s: "foo", n: 3, f: 3.0, arr: []string{"a", "b"}}, cmp.AllowUnexported(myCustomType{}))) + Expect(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).ShouldNot(Compare(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b", "c"}}, cmp.AllowUnexported(myCustomType{}))) + }) + }) +}) From 3a4f721264c6ccf4ddde8348ca915bdf931de496 Mon Sep 17 00:00:00 2001 From: tank Date: Sat, 23 Apr 2022 18:11:04 +0800 Subject: [PATCH 2/3] fix: use recover to let it as usual error handling --- matchers/compare_matcher.go | 13 ++++++++++++- matchers/compare_matcher_test.go | 20 +++++++------------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/matchers/compare_matcher.go b/matchers/compare_matcher.go index 645f36290..b180ee416 100644 --- a/matchers/compare_matcher.go +++ b/matchers/compare_matcher.go @@ -12,7 +12,7 @@ type CompareMatcher struct { Options cmp.Options } -func (matcher *CompareMatcher) Match(actual interface{}) (success bool, err error) { +func (matcher *CompareMatcher) Match(actual interface{}) (success bool, matchErr error) { if actual == nil && matcher.Expected == nil { return false, fmt.Errorf("Refusing to compare to .\nBe explicit and use BeNil() instead. This is to avoid mistakes where both sides of an assertion are erroneously uninitialized.") } @@ -25,6 +25,17 @@ func (matcher *CompareMatcher) Match(actual interface{}) (success bool, err erro } } + defer func() { + if r := recover(); r != nil { + success = false + if err, ok := r.(error); ok { + matchErr = err + } else if errMsg, ok := r.(string); ok { + matchErr = fmt.Errorf(errMsg) + } + } + }() + return cmp.Equal(actual, matcher.Expected, matcher.Options...), nil } diff --git a/matchers/compare_matcher_test.go b/matchers/compare_matcher_test.go index 8acbd0b36..1bc30b7b0 100644 --- a/matchers/compare_matcher_test.go +++ b/matchers/compare_matcher_test.go @@ -43,16 +43,17 @@ var _ = Describe("Compare", func() { }) Context("When asserting time with different location ", func() { - var t1, t2 time.Time + var t1, t2, t3 time.Time BeforeEach(func() { t1 = time.Time{} t2 = time.Time{}.Local() + t3 = t1.Add(time.Second) }) It("should do the right thing", func() { - Expect(t1).ShouldNot(Equal(t2)) Expect(t1).Should(Compare(t2)) + Expect(t1).ShouldNot(Compare(t3)) }) }) @@ -69,17 +70,10 @@ var _ = Describe("Compare", func() { s2 = structWithUnexportedFields{unexported: "unexported", Exported: "Exported"} }) - It("should panic with unexported field", func() { - defer func() { - if e := recover(); e != nil { - Expect(e).Should(HavePrefix("cannot handle unexported field at")) - } - }() - - matcher := &CompareMatcher{ - Expected: s1, - } - _, _ = matcher.Match(s2) + It("should get match err", func() { + success, err := (&CompareMatcher{Expected: s1}).Match(s2) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) }) It("should do the right thing", func() { From 9906c1508b6e44f70ed364f1295a3d53158356d6 Mon Sep 17 00:00:00 2001 From: tank Date: Wed, 27 Apr 2022 09:03:12 +0800 Subject: [PATCH 3/3] refactor: rename Compare -> BeComparableTo --- matchers.go | 6 +- ...matcher.go => be_comparable_to_matcher.go} | 8 +- matchers/be_comparable_to_matcher_test.go | 130 ++++++++++++++++++ matchers/compare_matcher_test.go | 130 ------------------ 4 files changed, 137 insertions(+), 137 deletions(-) rename matchers/{compare_matcher.go => be_comparable_to_matcher.go} (79%) create mode 100644 matchers/be_comparable_to_matcher_test.go delete mode 100644 matchers/compare_matcher_test.go diff --git a/matchers.go b/matchers.go index 6a17bbddc..82e5ebb98 100644 --- a/matchers.go +++ b/matchers.go @@ -27,10 +27,10 @@ func BeEquivalentTo(expected interface{}) types.GomegaMatcher { } } -//Compare uses gocmp.Equal to compare. You can pass cmp.Option as options. +//BeComparableTo uses gocmp.Equal to compare. You can pass cmp.Option as options. //It is an error for actual and expected to be nil. Use BeNil() instead. -func Compare(expected interface{}, opts ...cmp.Option) types.GomegaMatcher { - return &matchers.CompareMatcher{ +func BeComparableTo(expected interface{}, opts ...cmp.Option) types.GomegaMatcher { + return &matchers.BeComparableToMatcher{ Expected: expected, Options: opts, } diff --git a/matchers/compare_matcher.go b/matchers/be_comparable_to_matcher.go similarity index 79% rename from matchers/compare_matcher.go rename to matchers/be_comparable_to_matcher.go index b180ee416..2205d8c23 100644 --- a/matchers/compare_matcher.go +++ b/matchers/be_comparable_to_matcher.go @@ -7,12 +7,12 @@ import ( "github.com/onsi/gomega/format" ) -type CompareMatcher struct { +type BeComparableToMatcher struct { Expected interface{} Options cmp.Options } -func (matcher *CompareMatcher) Match(actual interface{}) (success bool, matchErr error) { +func (matcher *BeComparableToMatcher) Match(actual interface{}) (success bool, matchErr error) { if actual == nil && matcher.Expected == nil { return false, fmt.Errorf("Refusing to compare to .\nBe explicit and use BeNil() instead. This is to avoid mistakes where both sides of an assertion are erroneously uninitialized.") } @@ -39,10 +39,10 @@ func (matcher *CompareMatcher) Match(actual interface{}) (success bool, matchErr return cmp.Equal(actual, matcher.Expected, matcher.Options...), nil } -func (matcher *CompareMatcher) FailureMessage(actual interface{}) (message string) { +func (matcher *BeComparableToMatcher) FailureMessage(actual interface{}) (message string) { return cmp.Diff(matcher.Expected, actual) } -func (matcher *CompareMatcher) NegatedFailureMessage(actual interface{}) (message string) { +func (matcher *BeComparableToMatcher) NegatedFailureMessage(actual interface{}) (message string) { return format.Message(actual, "not to equal", matcher.Expected) } diff --git a/matchers/be_comparable_to_matcher_test.go b/matchers/be_comparable_to_matcher_test.go new file mode 100644 index 000000000..083d3c609 --- /dev/null +++ b/matchers/be_comparable_to_matcher_test.go @@ -0,0 +1,130 @@ +package matchers_test + +import ( + "errors" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/matchers" +) + +type wrapError struct { + msg string + err error +} + +func (e wrapError) Error() string { + return e.msg +} + +func (e wrapError) Unwrap() error { + return e.err +} + +var _ = Describe("BeComparableTo", func() { + When("asserting that nil is comparable to nil", func() { + It("should error", func() { + success, err := (&BeComparableToMatcher{Expected: nil}).Match(nil) + + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + }) + + Context("When asserting on nil", func() { + It("should do the right thing", func() { + Expect("foo").ShouldNot(BeComparableTo(nil)) + Expect(nil).ShouldNot(BeComparableTo(3)) + Expect([]int{1, 2}).ShouldNot(BeComparableTo(nil)) + }) + }) + + Context("When asserting time with different location ", func() { + var t1, t2, t3 time.Time + + BeforeEach(func() { + t1 = time.Time{} + t2 = time.Time{}.Local() + t3 = t1.Add(time.Second) + }) + + It("should do the right thing", func() { + Expect(t1).Should(BeComparableTo(t2)) + Expect(t1).ShouldNot(BeComparableTo(t3)) + }) + }) + + Context("When struct contain unexported fields", func() { + type structWithUnexportedFields struct { + unexported string + Exported string + } + + var s1, s2 structWithUnexportedFields + + BeforeEach(func() { + s1 = structWithUnexportedFields{unexported: "unexported", Exported: "Exported"} + s2 = structWithUnexportedFields{unexported: "unexported", Exported: "Exported"} + }) + + It("should get match err", func() { + success, err := (&BeComparableToMatcher{Expected: s1}).Match(s2) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + + It("should do the right thing", func() { + Expect(s1).Should(BeComparableTo(s2, cmpopts.IgnoreUnexported(structWithUnexportedFields{}))) + }) + }) + + Context("When compare error", func() { + var err1, err2 error + + It("not equal", func() { + err1 = errors.New("error") + err2 = errors.New("error") + Expect(err1).ShouldNot(BeComparableTo(err2, cmpopts.EquateErrors())) + }) + + It("equal if err1 is err2", func() { + err1 = errors.New("error") + err2 = &wrapError{ + msg: "some error", + err: err1, + } + + Expect(err1).Should(BeComparableTo(err2, cmpopts.EquateErrors())) + }) + }) + + Context("When asserting equal between objects", func() { + It("should do the right thing", func() { + Expect(5).Should(BeComparableTo(5)) + Expect(5.0).Should(BeComparableTo(5.0)) + + Expect(5).ShouldNot(BeComparableTo("5")) + Expect(5).ShouldNot(BeComparableTo(5.0)) + Expect(5).ShouldNot(BeComparableTo(3)) + + Expect("5").Should(BeComparableTo("5")) + Expect([]int{1, 2}).Should(BeComparableTo([]int{1, 2})) + Expect([]int{1, 2}).ShouldNot(BeComparableTo([]int{2, 1})) + Expect([]byte{'f', 'o', 'o'}).Should(BeComparableTo([]byte{'f', 'o', 'o'})) + Expect([]byte{'f', 'o', 'o'}).ShouldNot(BeComparableTo([]byte{'b', 'a', 'r'})) + Expect(map[string]string{"a": "b", "c": "d"}).Should(BeComparableTo(map[string]string{"a": "b", "c": "d"})) + Expect(map[string]string{"a": "b", "c": "d"}).ShouldNot(BeComparableTo(map[string]string{"a": "b", "c": "e"})) + + Expect(myCustomType{s: "abc", n: 3, f: 2.0, arr: []string{"a", "b"}}).Should(BeComparableTo(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}, cmpopts.IgnoreUnexported(myCustomType{}))) + + Expect(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).Should(BeComparableTo(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}, cmp.AllowUnexported(myCustomType{}))) + Expect(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).ShouldNot(BeComparableTo(myCustomType{s: "bar", n: 3, f: 2.0, arr: []string{"a", "b"}}, cmp.AllowUnexported(myCustomType{}))) + Expect(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).ShouldNot(BeComparableTo(myCustomType{s: "foo", n: 2, f: 2.0, arr: []string{"a", "b"}}, cmp.AllowUnexported(myCustomType{}))) + Expect(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).ShouldNot(BeComparableTo(myCustomType{s: "foo", n: 3, f: 3.0, arr: []string{"a", "b"}}, cmp.AllowUnexported(myCustomType{}))) + Expect(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).ShouldNot(BeComparableTo(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b", "c"}}, cmp.AllowUnexported(myCustomType{}))) + }) + }) +}) diff --git a/matchers/compare_matcher_test.go b/matchers/compare_matcher_test.go deleted file mode 100644 index 1bc30b7b0..000000000 --- a/matchers/compare_matcher_test.go +++ /dev/null @@ -1,130 +0,0 @@ -package matchers_test - -import ( - "errors" - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" - "time" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - . "github.com/onsi/gomega/matchers" -) - -type wrapError struct { - msg string - err error -} - -func (e wrapError) Error() string { - return e.msg -} - -func (e wrapError) Unwrap() error { - return e.err -} - -var _ = Describe("Compare", func() { - When("asserting that nil compare equal nil", func() { - It("should error", func() { - success, err := (&CompareMatcher{Expected: nil}).Match(nil) - - Expect(success).Should(BeFalse()) - Expect(err).Should(HaveOccurred()) - }) - }) - - Context("When asserting on nil", func() { - It("should do the right thing", func() { - Expect("foo").ShouldNot(Compare(nil)) - Expect(nil).ShouldNot(Compare(3)) - Expect([]int{1, 2}).ShouldNot(Compare(nil)) - }) - }) - - Context("When asserting time with different location ", func() { - var t1, t2, t3 time.Time - - BeforeEach(func() { - t1 = time.Time{} - t2 = time.Time{}.Local() - t3 = t1.Add(time.Second) - }) - - It("should do the right thing", func() { - Expect(t1).Should(Compare(t2)) - Expect(t1).ShouldNot(Compare(t3)) - }) - }) - - Context("When struct contain unexported fields", func() { - type structWithUnexportedFields struct { - unexported string - Exported string - } - - var s1, s2 structWithUnexportedFields - - BeforeEach(func() { - s1 = structWithUnexportedFields{unexported: "unexported", Exported: "Exported"} - s2 = structWithUnexportedFields{unexported: "unexported", Exported: "Exported"} - }) - - It("should get match err", func() { - success, err := (&CompareMatcher{Expected: s1}).Match(s2) - Expect(success).Should(BeFalse()) - Expect(err).Should(HaveOccurred()) - }) - - It("should do the right thing", func() { - Expect(s1).Should(Compare(s2, cmpopts.IgnoreUnexported(structWithUnexportedFields{}))) - }) - }) - - Context("When compare error", func() { - var err1, err2 error - - It("not equal", func() { - err1 = errors.New("error") - err2 = errors.New("error") - Expect(err1).ShouldNot(Compare(err2, cmpopts.EquateErrors())) - }) - - It("equal if err1 is err2", func() { - err1 = errors.New("error") - err2 = &wrapError{ - msg: "some error", - err: err1, - } - - Expect(err1).Should(Compare(err2, cmpopts.EquateErrors())) - }) - }) - - Context("When asserting equal between objects", func() { - It("should do the right thing", func() { - Expect(5).Should(Compare(5)) - Expect(5.0).Should(Compare(5.0)) - - Expect(5).ShouldNot(Compare("5")) - Expect(5).ShouldNot(Compare(5.0)) - Expect(5).ShouldNot(Compare(3)) - - Expect("5").Should(Compare("5")) - Expect([]int{1, 2}).Should(Compare([]int{1, 2})) - Expect([]int{1, 2}).ShouldNot(Compare([]int{2, 1})) - Expect([]byte{'f', 'o', 'o'}).Should(Compare([]byte{'f', 'o', 'o'})) - Expect([]byte{'f', 'o', 'o'}).ShouldNot(Compare([]byte{'b', 'a', 'r'})) - Expect(map[string]string{"a": "b", "c": "d"}).Should(Compare(map[string]string{"a": "b", "c": "d"})) - Expect(map[string]string{"a": "b", "c": "d"}).ShouldNot(Compare(map[string]string{"a": "b", "c": "e"})) - - Expect(myCustomType{s: "abc", n: 3, f: 2.0, arr: []string{"a", "b"}}).Should(Compare(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}, cmpopts.IgnoreUnexported(myCustomType{}))) - - Expect(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).Should(Compare(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}, cmp.AllowUnexported(myCustomType{}))) - Expect(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).ShouldNot(Compare(myCustomType{s: "bar", n: 3, f: 2.0, arr: []string{"a", "b"}}, cmp.AllowUnexported(myCustomType{}))) - Expect(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).ShouldNot(Compare(myCustomType{s: "foo", n: 2, f: 2.0, arr: []string{"a", "b"}}, cmp.AllowUnexported(myCustomType{}))) - Expect(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).ShouldNot(Compare(myCustomType{s: "foo", n: 3, f: 3.0, arr: []string{"a", "b"}}, cmp.AllowUnexported(myCustomType{}))) - Expect(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).ShouldNot(Compare(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b", "c"}}, cmp.AllowUnexported(myCustomType{}))) - }) - }) -})