Skip to content

Commit e64f0e2

Browse files
committed
ShouldEqual is now functionally equivalent to ShouldResemble.
No longer depending on oglematchers for any equality assertions.
1 parent b084782 commit e64f0e2

9 files changed

+242
-166
lines changed

assert/assert_failed_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ func (this *FailedResultFixture) Setup() {
2626
func (this *FailedResultFixture) assertLogMessageContents() {
2727
this.So(this.result.logger.Log.String(), should.ContainSubstring, "✘ So(actual: 1, should.Equal, expected: [2])")
2828
this.So(this.result.logger.Log.String(), should.ContainSubstring, "Assertion failure at ")
29-
this.So(this.result.logger.Log.String(), should.EndWith, "Expected: '2'\nActual: '1'\n(Should be equal)\n")
29+
this.So(this.result.logger.Log.String(), should.EndWith, "Expected: 2\nActual: 1\n(Should equal)!\n")
3030
}
3131

3232
func (this *FailedResultFixture) TestQueryFunctions() {

equal_method.go

+33-43
Original file line numberDiff line numberDiff line change
@@ -2,69 +2,59 @@ package assertions
22

33
import "reflect"
44

5-
type equalityMethodSpecification struct {
6-
a any
7-
b any
5+
type equalityMethodSpecification struct{}
86

9-
aType reflect.Type
10-
bType reflect.Type
11-
12-
equalMethod reflect.Value
13-
}
14-
15-
func newEqualityMethodSpecification(a, b any) *equalityMethodSpecification {
16-
return &equalityMethodSpecification{
17-
a: a,
18-
b: b,
19-
}
20-
}
21-
22-
func (this *equalityMethodSpecification) IsSatisfied() bool {
23-
if !this.bothAreSameType() {
7+
func (this equalityMethodSpecification) assertable(a, b any) bool {
8+
if !bothAreSameType(a, b) {
249
return false
2510
}
26-
if !this.typeHasEqualMethod() {
11+
if !typeHasEqualMethod(a) {
2712
return false
2813
}
29-
if !this.equalMethodReceivesSameTypeForComparison() {
14+
if !equalMethodReceivesSameTypeForComparison(a) {
3015
return false
3116
}
32-
if !this.equalMethodReturnsBool() {
17+
if !equalMethodReturnsBool(a) {
3318
return false
3419
}
3520
return true
3621
}
37-
38-
func (this *equalityMethodSpecification) bothAreSameType() bool {
39-
this.aType = reflect.TypeOf(this.a)
40-
if this.aType == nil {
22+
func bothAreSameType(a, b any) bool {
23+
aType := reflect.TypeOf(a)
24+
if aType == nil {
4125
return false
4226
}
43-
if this.aType.Kind() == reflect.Ptr {
44-
this.aType = this.aType.Elem()
27+
if aType.Kind() == reflect.Ptr {
28+
aType = aType.Elem()
4529
}
46-
this.bType = reflect.TypeOf(this.b)
47-
return this.aType == this.bType
30+
bType := reflect.TypeOf(b)
31+
return aType == bType
4832
}
49-
func (this *equalityMethodSpecification) typeHasEqualMethod() bool {
50-
aInstance := reflect.ValueOf(this.a)
51-
this.equalMethod = aInstance.MethodByName("Equal")
52-
return this.equalMethod != reflect.Value{}
33+
func typeHasEqualMethod(a any) bool {
34+
aInstance := reflect.ValueOf(a)
35+
equalMethod := aInstance.MethodByName("Equal")
36+
return equalMethod != reflect.Value{}
5337
}
54-
55-
func (this *equalityMethodSpecification) equalMethodReceivesSameTypeForComparison() bool {
56-
signature := this.equalMethod.Type()
57-
return signature.NumIn() == 1 && signature.In(0) == this.aType
38+
func equalMethodReceivesSameTypeForComparison(a any) bool {
39+
aType := reflect.TypeOf(a)
40+
if aType.Kind() == reflect.Ptr {
41+
aType = aType.Elem()
42+
}
43+
aInstance := reflect.ValueOf(a)
44+
equalMethod := aInstance.MethodByName("Equal")
45+
signature := equalMethod.Type()
46+
return signature.NumIn() == 1 && signature.In(0) == aType
5847
}
59-
60-
func (this *equalityMethodSpecification) equalMethodReturnsBool() bool {
61-
signature := this.equalMethod.Type()
48+
func equalMethodReturnsBool(a any) bool {
49+
aInstance := reflect.ValueOf(a)
50+
equalMethod := aInstance.MethodByName("Equal")
51+
signature := equalMethod.Type()
6252
return signature.NumOut() == 1 && signature.Out(0) == reflect.TypeOf(true)
6353
}
6454

65-
func (this *equalityMethodSpecification) AreEqual() bool {
66-
a := reflect.ValueOf(this.a)
67-
b := reflect.ValueOf(this.b)
55+
func (this equalityMethodSpecification) passes(A, B any) bool {
56+
a := reflect.ValueOf(A)
57+
b := reflect.ValueOf(B)
6858
return areEqual(a, b) && areEqual(b, a)
6959
}
7060
func areEqual(receiver reflect.Value, argument reflect.Value) bool {

equal_method_test.go

+36-36
Original file line numberDiff line numberDiff line change
@@ -15,116 +15,116 @@ type EqualityFixture struct {
1515
}
1616

1717
func (this *EqualityFixture) TestNilNil() {
18-
spec := newEqualityMethodSpecification(nil, nil)
19-
this.So(spec.IsSatisfied(), ShouldBeFalse)
18+
spec := equalityMethodSpecification{}
19+
this.So(spec.assertable(nil, nil), ShouldBeFalse)
2020
}
2121

2222
func (this *EqualityFixture) TestEligible1() {
2323
a := Eligible1{"hi"}
2424
b := Eligible1{"hi"}
25-
specification := newEqualityMethodSpecification(a, b)
26-
this.So(specification.IsSatisfied(), ShouldBeTrue)
27-
this.So(specification.AreEqual(), ShouldBeTrue)
25+
specification := equalityMethodSpecification{}
26+
this.So(specification.assertable(a, b), ShouldBeTrue)
27+
this.So(specification.passes(a, b), ShouldBeTrue)
2828
}
2929

3030
func (this *EqualityFixture) TestAreEqual() {
3131
a := Eligible1{"hi"}
3232
b := Eligible1{"hi"}
33-
specification := newEqualityMethodSpecification(a, b)
34-
this.So(specification.IsSatisfied(), ShouldBeTrue)
35-
this.So(specification.AreEqual(), ShouldBeTrue)
33+
specification := equalityMethodSpecification{}
34+
this.So(specification.assertable(a, b), ShouldBeTrue)
35+
this.So(specification.passes(a, b), ShouldBeTrue)
3636
}
3737

3838
func (this *EqualityFixture) TestAreNotEqual() {
3939
a := Eligible1{"hi"}
4040
b := Eligible1{"bye"}
41-
specification := newEqualityMethodSpecification(a, b)
42-
this.So(specification.IsSatisfied(), ShouldBeTrue)
43-
this.So(specification.AreEqual(), ShouldBeFalse)
41+
specification := equalityMethodSpecification{}
42+
this.So(specification.assertable(a, b), ShouldBeTrue)
43+
this.So(specification.passes(a, b), ShouldBeFalse)
4444
}
4545

4646
func (this *EqualityFixture) TestEligible2() {
4747
a := Eligible2{"hi"}
4848
b := Eligible2{"hi"}
49-
specification := newEqualityMethodSpecification(a, b)
50-
this.So(specification.IsSatisfied(), ShouldBeTrue)
49+
specification := equalityMethodSpecification{}
50+
this.So(specification.assertable(a, b), ShouldBeTrue)
5151
}
5252

5353
func (this *EqualityFixture) TestEligible1_PointerReceiver() {
5454
a := &Eligible1{"hi"}
5555
b := Eligible1{"hi"}
5656
this.So(a.Equal(b), ShouldBeTrue)
57-
specification := newEqualityMethodSpecification(a, b)
58-
this.So(specification.IsSatisfied(), ShouldBeTrue)
57+
specification := equalityMethodSpecification{}
58+
this.So(specification.assertable(a, b), ShouldBeTrue)
5959
}
6060

6161
func (this *EqualityFixture) TestIneligible_PrimitiveTypes() {
62-
specification := newEqualityMethodSpecification(1, 1)
63-
this.So(specification.IsSatisfied(), ShouldBeFalse)
62+
specification := equalityMethodSpecification{}
63+
this.So(specification.assertable(1, 1), ShouldBeFalse)
6464
}
6565

6666
func (this *EqualityFixture) TestIneligible_DisparateTypes() {
6767
a := Eligible1{"hi"}
6868
b := Eligible2{"hi"}
69-
specification := newEqualityMethodSpecification(a, b)
70-
this.So(specification.IsSatisfied(), ShouldBeFalse)
69+
specification := equalityMethodSpecification{}
70+
this.So(specification.assertable(a, b), ShouldBeFalse)
7171
}
7272

7373
func (this *EqualityFixture) TestIneligible_NoEqualMethod() {
7474
a := Ineligible_NoEqualMethod{}
7575
b := Ineligible_NoEqualMethod{}
76-
specification := newEqualityMethodSpecification(a, b)
77-
this.So(specification.IsSatisfied(), ShouldBeFalse)
76+
specification := equalityMethodSpecification{}
77+
this.So(specification.assertable(a, b), ShouldBeFalse)
7878
}
7979

8080
func (this *EqualityFixture) TestIneligible_EqualMethodReceivesNoInput() {
8181
a := Ineligible_EqualMethodNoInputs{}
8282
b := Ineligible_EqualMethodNoInputs{}
83-
specification := newEqualityMethodSpecification(a, b)
84-
this.So(specification.IsSatisfied(), ShouldBeFalse)
83+
specification := equalityMethodSpecification{}
84+
this.So(specification.assertable(a, b), ShouldBeFalse)
8585
}
8686

8787
func (this *EqualityFixture) TestIneligible_EqualMethodReceivesTooManyInputs() {
8888
a := Ineligible_EqualMethodTooManyInputs{}
8989
b := Ineligible_EqualMethodTooManyInputs{}
90-
specification := newEqualityMethodSpecification(a, b)
91-
this.So(specification.IsSatisfied(), ShouldBeFalse)
90+
specification := equalityMethodSpecification{}
91+
this.So(specification.assertable(a, b), ShouldBeFalse)
9292
}
9393

9494
func (this *EqualityFixture) TestIneligible_EqualMethodReceivesWrongInput() {
9595
a := Ineligible_EqualMethodWrongInput{}
9696
b := Ineligible_EqualMethodWrongInput{}
97-
specification := newEqualityMethodSpecification(a, b)
98-
this.So(specification.IsSatisfied(), ShouldBeFalse)
97+
specification := equalityMethodSpecification{}
98+
this.So(specification.assertable(a, b), ShouldBeFalse)
9999
}
100100

101101
func (this *EqualityFixture) TestIneligible_EqualMethodReturnsNoOutputs() {
102102
a := Ineligible_EqualMethodNoOutputs{}
103103
b := Ineligible_EqualMethodNoOutputs{}
104-
specification := newEqualityMethodSpecification(a, b)
105-
this.So(specification.IsSatisfied(), ShouldBeFalse)
104+
specification := equalityMethodSpecification{}
105+
this.So(specification.assertable(a, b), ShouldBeFalse)
106106
}
107107

108108
func (this *EqualityFixture) TestIneligible_EqualMethodReturnsTooManyOutputs() {
109109
a := Ineligible_EqualMethodTooManyOutputs{}
110110
b := Ineligible_EqualMethodTooManyOutputs{}
111-
specification := newEqualityMethodSpecification(a, b)
112-
this.So(specification.IsSatisfied(), ShouldBeFalse)
111+
specification := equalityMethodSpecification{}
112+
this.So(specification.assertable(a, b), ShouldBeFalse)
113113
}
114114

115115
func (this *EqualityFixture) TestIneligible_EqualMethodReturnsWrongOutputs() {
116116
a := Ineligible_EqualMethodWrongOutput{}
117117
b := Ineligible_EqualMethodWrongOutput{}
118-
specification := newEqualityMethodSpecification(a, b)
119-
this.So(specification.IsSatisfied(), ShouldBeFalse)
118+
specification := equalityMethodSpecification{}
119+
this.So(specification.assertable(a, b), ShouldBeFalse)
120120
}
121121

122122
func (this *EqualityFixture) TestEligibleAsymmetric_EqualMethodResultDiffersWhenArgumentsInverted() {
123123
a := EligibleAsymmetric{a: 0}
124124
b := EligibleAsymmetric{a: 1}
125-
specification := newEqualityMethodSpecification(a, b)
126-
this.So(specification.IsSatisfied(), ShouldBeTrue)
127-
this.So(specification.AreEqual(), ShouldBeFalse)
125+
specification := equalityMethodSpecification{}
126+
this.So(specification.assertable(a, b), ShouldBeTrue)
127+
this.So(specification.passes(a, b), ShouldBeFalse)
128128
}
129129

130130
/**************************************************************************/

equality.go

+22-53
Original file line numberDiff line numberDiff line change
@@ -9,48 +9,37 @@ import (
99
"strings"
1010

1111
"github.com/smarty/assertions/internal/go-render/render"
12-
"github.com/smarty/assertions/internal/oglematchers"
1312
)
1413

1514
// ShouldEqual receives exactly two parameters and does an equality check
1615
// using the following semantics:
17-
// 1. If the expected and actual values implement an Equal method in the form
18-
// `func (this T) Equal(that T) bool` then call the method. If true, they are equal.
19-
// 2. The expected and actual values are judged equal or not by oglematchers.Equals.
16+
// It uses reflect.DeepEqual in most cases, but also compares numerics
17+
// regardless of specific type and compares time.Time values using the
18+
// time.Equal method.
2019
func ShouldEqual(actual any, expected ...any) string {
2120
if message := need(1, expected); message != success {
2221
return message
2322
}
2423
return shouldEqual(actual, expected[0])
2524
}
26-
func shouldEqual(actual, expected any) (message string) {
27-
defer func() {
28-
if r := recover(); r != nil {
29-
message = serializer.serialize(expected, actual, composeEqualityMismatchMessage(expected, actual))
25+
func shouldEqual(actual, expected any) string {
26+
for _, spec := range equalitySpecs {
27+
if !spec.assertable(actual, expected) {
28+
continue
3029
}
31-
}()
32-
33-
if spec := newEqualityMethodSpecification(expected, actual); spec.IsSatisfied() && spec.AreEqual() {
34-
return success
35-
} else if matchError := oglematchers.Equals(expected).Matches(actual); matchError == nil {
36-
return success
30+
if spec.passes(actual, expected) {
31+
return success
32+
}
33+
break
3734
}
38-
39-
return serializer.serialize(expected, actual, composeEqualityMismatchMessage(expected, actual))
40-
}
41-
func composeEqualityMismatchMessage(expected, actual any) string {
42-
var (
43-
renderedExpected = fmt.Sprintf("%v", expected)
44-
renderedActual = fmt.Sprintf("%v", actual)
45-
)
46-
47-
if renderedExpected != renderedActual {
48-
return fmt.Sprintf(shouldHaveBeenEqual+composePrettyDiff(renderedExpected, renderedActual), expected, actual)
49-
} else if reflect.TypeOf(expected) != reflect.TypeOf(actual) {
50-
return fmt.Sprintf(shouldHaveBeenEqualTypeMismatch, expected, expected, actual, actual)
51-
} else {
52-
return fmt.Sprintf(shouldHaveBeenEqualNoResemblance, renderedExpected)
35+
renderedExpected, renderedActual := render.Render(expected), render.Render(actual)
36+
if renderedActual == renderedExpected {
37+
message := fmt.Sprintf(shouldHaveResembledButTypeDiff, renderedExpected, renderedActual)
38+
return serializer.serializeDetailed(expected, actual, message)
5339
}
40+
message := fmt.Sprintf(shouldHaveResembled, renderedExpected, renderedActual) +
41+
composePrettyDiff(renderedExpected, renderedActual)
42+
return serializer.serializeDetailed(expected, actual, message)
5443
}
5544

5645
// ShouldNotEqual receives exactly two parameters and does an inequality check.
@@ -179,34 +168,14 @@ func remarshal(value string) (string, error) {
179168
return string(canonical), nil
180169
}
181170

182-
// ShouldResemble receives exactly two parameters and does a deep equal check (see reflect.DeepEqual)
171+
// ShouldResemble is an alias for ShouldEqual.
183172
func ShouldResemble(actual any, expected ...any) string {
184-
if message := need(1, expected); message != success {
185-
return message
186-
}
187-
188-
if matchError := oglematchers.DeepEquals(expected[0]).Matches(actual); matchError != nil {
189-
renderedExpected, renderedActual := render.Render(expected[0]), render.Render(actual)
190-
if renderedActual == renderedExpected {
191-
message := fmt.Sprintf(shouldHaveResembledButTypeDiff, renderedExpected, renderedActual)
192-
return serializer.serializeDetailed(expected[0], actual, message)
193-
}
194-
message := fmt.Sprintf(shouldHaveResembled, renderedExpected, renderedActual) +
195-
composePrettyDiff(renderedExpected, renderedActual)
196-
return serializer.serializeDetailed(expected[0], actual, message)
197-
}
198-
199-
return success
173+
return ShouldEqual(actual, expected...)
200174
}
201175

202-
// ShouldNotResemble receives exactly two parameters and does an inverse deep equal check (see reflect.DeepEqual)
176+
// ShouldNotResemble is an alias for ShouldNotEqual.
203177
func ShouldNotResemble(actual any, expected ...any) string {
204-
if message := need(1, expected); message != success {
205-
return message
206-
} else if ShouldResemble(actual, expected[0]) == success {
207-
return fmt.Sprintf(shouldNotHaveResembled, render.Render(actual), render.Render(expected[0]))
208-
}
209-
return success
178+
return ShouldNotEqual(actual, expected...)
210179
}
211180

212181
// ShouldPointTo receives exactly two parameters and checks to see that they point to the same address.

0 commit comments

Comments
 (0)