From 396b1a3d1908d784b101e915f54f58951933a90b Mon Sep 17 00:00:00 2001 From: bayashi <42190+bayashi@users.noreply.github.com> Date: Thu, 2 May 2024 15:09:49 +0000 Subject: [PATCH] Add `Cmp`, `CmpAllowUnexported` and `CmpOpt` methods --- README.md | 1 + actually.go | 3 +++ assert_cmp.go | 60 ++++++++++++++++++++++++++++++++++++++++++++++ assert_cmp_test.go | 41 +++++++++++++++++++++++++++++++ go.mod | 5 +++- go.sum | 2 ++ 6 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 assert_cmp.go create mode 100644 assert_cmp_test.go diff --git a/README.md b/README.md index 302a35b..0d92e93 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,7 @@ func getLove() (bool, error) { ### [For 2 objects](https://github.com/bayashi/actually/wiki/All-assertion-methods#assertion-for-2-objects) * Same, SameConvertibleNumber, SamePointer, SameType +* Cmp, CmpAllowUnexported, (CmpOpt) * NotSame, NotSameConvertibleNumber, NotSamePointer, NotSameType ### [For panic](https://github.com/bayashi/actually/wiki/All-assertion-methods#assertion-for-panic) diff --git a/actually.go b/actually.go index 9b32b1f..9f4496c 100644 --- a/actually.go +++ b/actually.go @@ -4,6 +4,8 @@ package actually import ( "fmt" "testing" + + "github.com/google/go-cmp/cmp" ) // testingA is a context of the test @@ -18,6 +20,7 @@ type testingA struct { name string failed bool debugInfo []map[string][]any + cmpOpts []cmp.Option } // Got sets the value you actually got. Got() creates *testingA and returns it. diff --git a/assert_cmp.go b/assert_cmp.go new file mode 100644 index 0000000..45a1cb0 --- /dev/null +++ b/assert_cmp.go @@ -0,0 +1,60 @@ +package actually + +import ( + "testing" + + "github.com/google/go-cmp/cmp" +) + +// Cmp method gets the differences between two objects by go-cmp.Diff. +// https://pkg.go.dev/github.com/google/go-cmp/cmp#Diff +/* + actually.Got(obj1).Expect(obj2).Cmp(t) +*/ +// If you need to set cmp.Option, then you shoud use `CmpOpt(cmp.Option)` method before calling Cmp. +// Cmp method is just a wrapper of go-cmp.Diff. So, it's same that unexported fields are not compared by default; +// they result in panics unless suppressed by using an Ignore option. It may panic if it cannot compare the values. +func (a *testingA) Cmp(t *testing.T, testNames ...string) *testingA { + invalidCallForSame(a) + a.name = a.naming(testNames...) + a.t = t + a.t.Helper() + + if diff := cmp.Diff(a.expect, a.got, a.cmpOpts...); diff != "" { + return a.fail(reportForSame(a).Message("Diff details", diff), reason_NotSame) + } + + return a +} + +// CmpAllowUnexported method gets the differences between two objects by go-cmp.Diff with cmp.AllowUnexported option. +// It accepts unexported methods to compare instead panic. If you would like to ignore unexported methods, +// then you can use cmpopts.IgnoreUnexported or some cmpopt's options to ignore. +func (a *testingA) CmpAllowUnexported(t *testing.T, testNames ...string) *testingA { + invalidCallForSame(a) + a.name = a.naming(testNames...) + a.t = t + a.t.Helper() + + a.CmpOpt(cmp.AllowUnexported(a.got)) + + if diff := cmp.Diff(a.expect, a.got, a.cmpOpts...); diff != "" { + return a.fail(reportForSame(a).Message("Diff details", diff), reason_NotSame) + } + + return a +} + +// CmpOpt method sets/adds options for Cmp* methods. +// There is no method to reset cmpOpts. Just set all opts at one time, or add opts. +/* + actually.Got(obj1).Expect(obj2).CmpOpt(cmpopts.IgnoreFields(Foo{}, "Field")).Cmp(t) +*/ +// ref: +// * https://pkg.go.dev/github.com/google/go-cmp/cmp#Option +// * https://pkg.go.dev/github.com/google/go-cmp/cmp/cmpopts +func (a *testingA) CmpOpt(cmpOpts ...cmp.Option) *testingA { + a.cmpOpts = append(a.cmpOpts, cmpOpts...) + + return a +} diff --git a/assert_cmp_test.go b/assert_cmp_test.go new file mode 100644 index 0000000..b66f7fa --- /dev/null +++ b/assert_cmp_test.go @@ -0,0 +1,41 @@ +package actually + +import ( + "testing" +) + +func TestCmp(t *testing.T) { + Got(123).Expect(123).Cmp(t) +} + +func TestCmp_Fail(t *testing.T) { + stubConfirm(t, func() { + Got(123).Expect(456).Cmp(t) + }, "Not same value") +} + +func TestCmpAllowUnexported(t *testing.T) { + x := struct { + id int + Name string + }{ + id: 1, + Name: "aiko", + } + Got(x).Expect(x).CmpAllowUnexported(t) +} + +func TestCmpAllowUnexported_Fail(t *testing.T) { + x := struct { + id int + Name string + }{ + id: 1, + Name: "aiko", + } + y := x + y.id = 2 + stubConfirm(t, func() { + Got(x).Expect(y).CmpAllowUnexported(t) + }, "Not same value") +} diff --git a/go.mod b/go.mod index c27c05f..e48f3ed 100644 --- a/go.mod +++ b/go.mod @@ -6,4 +6,7 @@ require github.com/pmezard/go-difflib v1.0.0 // indirect require github.com/bayashi/witness v0.0.19 -require github.com/davecgh/go-spew v1.1.1 // indirect +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/google/go-cmp v0.6.0 +) diff --git a/go.sum b/go.sum index 6d1e125..9c9a8b1 100644 --- a/go.sum +++ b/go.sum @@ -2,5 +2,7 @@ github.com/bayashi/witness v0.0.19 h1:UC8jpJMqAHMgseA6p4SyY8PZZWl46vaSI8xW7En+5M github.com/bayashi/witness v0.0.19/go.mod h1:xxXU08y35qzkp0kDRGVYuvHB5JVxFKe6vF16puu7gEo= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=