Skip to content

Commit ebb5636

Browse files
committed
feat: add Equal and NotEqual.
1 parent e894f0f commit ebb5636

File tree

5 files changed

+325
-8
lines changed

5 files changed

+325
-8
lines changed

builtin.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,38 @@ func NotDeepEqualNow(t *testing.T, actual, expect any, message ...string) error
3636
return tryNotDeepEqual(t, true, actual, expect, message...)
3737
}
3838

39+
// Equal tests the equality between actual and expect parameters. It'll set the result to fail if
40+
// they are not equal, and it doesn't stop the execution.
41+
func Equal(t *testing.T, actual, expect any, message ...string) error {
42+
t.Helper()
43+
44+
return tryEqual(t, false, actual, expect, message...)
45+
}
46+
47+
// EqualNow tests the equality between actual and expect parameters, and it'll stop the execution
48+
// if they are not equal.
49+
func EqualNow(t *testing.T, actual, expect any, message ...string) error {
50+
t.Helper()
51+
52+
return tryEqual(t, true, actual, expect, message...)
53+
}
54+
55+
// NotEqual tests the inequality between actual and expected parameters. It'll set the result to
56+
// fail if they are equal, but it doesn't stop the execution.
57+
func NotEqual(t *testing.T, actual, expect any, message ...string) error {
58+
t.Helper()
59+
60+
return tryNotEqual(t, false, actual, expect, message...)
61+
}
62+
63+
// NotEqualNow tests the inequality between actual and expected parameters, and it'll stop the
64+
// execution if they are equal.
65+
func NotEqualNow(t *testing.T, actual, expect any, message ...string) error {
66+
t.Helper()
67+
68+
return tryNotEqual(t, true, actual, expect, message...)
69+
}
70+
3971
// Nil tests whether a value is nil or not, and it'll fail when the value is not nil. It will
4072
// always return false if the value is a bool, an integer, a floating number, a complex, or a
4173
// string.

equal.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,68 @@ func tryNotDeepEqual(t *testing.T, failedNow bool, actual, expect any, message .
6868
return err
6969
}
7070

71+
// Equal tests the equality between actual and expect parameters. It'll set the result to fail if
72+
// they are not equal, and it doesn't stop the execution.
73+
func (a *Assertion) Equal(actual, expect any, message ...string) error {
74+
a.Helper()
75+
76+
return tryEqual(a.T, false, actual, expect, message...)
77+
}
78+
79+
// EqualNow tests the equality between actual and expect parameters, and it'll stop the execution
80+
// if they are not equal.
81+
func (a *Assertion) EqualNow(actual, expect any, message ...string) error {
82+
a.Helper()
83+
84+
return tryEqual(a.T, true, actual, expect, message...)
85+
}
86+
87+
// NotEqual tests the inequality between actual and expected parameters. It'll set the result to
88+
// fail if they are equal, but it doesn't stop the execution.
89+
func (a *Assertion) NotEqual(actual, expect any, message ...string) error {
90+
a.Helper()
91+
92+
return tryNotEqual(a.T, false, actual, expect, message...)
93+
}
94+
95+
// NotEqualNow tests the inequality between actual and expected parameters, and it'll stop the
96+
// execution if they are equal.
97+
func (a *Assertion) NotEqualNow(actual, expect any, message ...string) error {
98+
a.Helper()
99+
100+
return tryNotEqual(a.T, true, actual, expect, message...)
101+
}
102+
103+
// tryEqual try to testing the equality between actual and expect values, and it'll fail if the
104+
// values are not equal.
105+
func tryEqual(t *testing.T, failedNow bool, actual, expect any, message ...string) error {
106+
t.Helper()
107+
108+
if isEqual(actual, expect) {
109+
return nil
110+
}
111+
112+
err := newAssertionError(fmt.Sprintf("%v == %v", actual, expect), message...)
113+
failed(t, err, failedNow)
114+
115+
return err
116+
}
117+
118+
// tryNotEqual try to testing the inequality between actual and expect values, and it'll fail if
119+
// the values are equal.
120+
func tryNotEqual(t *testing.T, failedNow bool, actual, expect any, message ...string) error {
121+
t.Helper()
122+
123+
if !isEqual(actual, expect) {
124+
return nil
125+
}
126+
127+
err := newAssertionError(fmt.Sprintf("%v != %v", actual, expect), message...)
128+
failed(t, err, failedNow)
129+
130+
return err
131+
}
132+
71133
// Nil tests whether a value is nil or not, and it'll fail when the value is not nil. It will
72134
// always return false if the value is a bool, an integer, a floating number, a complex, or a
73135
// string.

equal_test.go

Lines changed: 114 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,32 +47,32 @@ func testDeepEqualAndNotDeepEqual(t *testing.T, assertion *Assertion, v1, v2 any
4747
func testDeepEqual(t *testing.T, assertion *Assertion, v1, v2 any, isEqual bool) {
4848
err := assertion.DeepEqual(v1, v2)
4949
if isEqual && err != nil {
50-
t.Errorf("Equal(%v, %v) = %v, want = nil", v1, v2, err)
50+
t.Errorf("DeepEqual(%v, %v) = %v, want = nil", v1, v2, err)
5151
} else if !isEqual && err == nil {
52-
t.Errorf("Equal(%v, %v) = nil, want = error", v1, v2)
52+
t.Errorf("DeepEqual(%v, %v) = nil, want = error", v1, v2)
5353
}
5454

5555
err = DeepEqual(assertion.T, v1, v2)
5656
if isEqual && err != nil {
57-
t.Errorf("Equal(%v, %v) = %v, want = nil", v1, v2, err)
57+
t.Errorf("DeepEqual(%v, %v) = %v, want = nil", v1, v2, err)
5858
} else if !isEqual && err == nil {
59-
t.Errorf("Equal(%v, %v) = nil, want = error", v1, v2)
59+
t.Errorf("DeepEqual(%v, %v) = nil, want = error", v1, v2)
6060
}
6161
}
6262

6363
func testNotDeepEqual(t *testing.T, assertion *Assertion, v1, v2 any, isEqual bool) {
6464
err := assertion.NotDeepEqual(v1, v2)
6565
if isEqual && err == nil {
66-
t.Errorf("NotEqual(%v, %v) = nil, want = error", v1, v2)
66+
t.Errorf("NotDeepEqual(%v, %v) = nil, want = error", v1, v2)
6767
} else if !isEqual && err != nil {
68-
t.Errorf("NotEqual(%v, %v) = %v, want = nil", v1, v2, err)
68+
t.Errorf("NotDeepEqual(%v, %v) = %v, want = nil", v1, v2, err)
6969
}
7070

7171
err = NotDeepEqual(assertion.T, v1, v2)
7272
if isEqual && err == nil {
73-
t.Errorf("NotEqual(%v, %v) = nil, want = error", v1, v2)
73+
t.Errorf("NotDeepEqual(%v, %v) = nil, want = error", v1, v2)
7474
} else if !isEqual && err != nil {
75-
t.Errorf("NotEqual(%v, %v) = %v, want = nil", v1, v2, err)
75+
t.Errorf("NotDeepEqual(%v, %v) = %v, want = nil", v1, v2, err)
7676
}
7777
}
7878

@@ -116,6 +116,112 @@ func testNotDeepEqualNow(t *testing.T, assertion *Assertion, v1, v2 any, isEqual
116116
}
117117
}
118118

119+
func TestEqualAndNotEqual(t *testing.T) {
120+
mockT := new(testing.T)
121+
assertion := New(mockT)
122+
123+
testEqualAndNotEqual(t, assertion, 1, 1, true)
124+
testEqualAndNotEqual(t, assertion, 1, 2, false)
125+
testEqualAndNotEqual(t, assertion, 1, int64(1), true)
126+
testEqualAndNotEqual(t, assertion, 1, 1.0, false)
127+
testEqualAndNotEqual(t, assertion, 1, "1", false)
128+
testEqualAndNotEqual(t, assertion, 1, '1', false)
129+
testEqualAndNotEqual(t, assertion, 1, []int{1}, false)
130+
testEqualAndNotEqual(t, assertion, []int{1}, []int{1}, true)
131+
132+
obj1 := testStruct{v: 1}
133+
obj2 := testStruct{v: 1}
134+
135+
testEqualAndNotEqual(t, assertion, obj1, obj2, true)
136+
testEqualAndNotEqual(t, assertion, obj1, &obj2, false)
137+
testEqualAndNotEqual(t, assertion, &obj1, &obj2, false)
138+
139+
obj2.v = 2
140+
testEqualAndNotEqual(t, assertion, obj1, obj2, false)
141+
}
142+
143+
func testEqualAndNotEqual(t *testing.T, assertion *Assertion, v1, v2 any, isEqual bool) {
144+
testEqual(t, assertion, v1, v2, isEqual)
145+
146+
testNotEqual(t, assertion, v1, v2, isEqual)
147+
148+
testEqualNow(t, assertion, v1, v2, isEqual)
149+
150+
testNotEqualNow(t, assertion, v1, v2, isEqual)
151+
}
152+
153+
func testEqual(t *testing.T, assertion *Assertion, v1, v2 any, isEqual bool) {
154+
err := assertion.Equal(v1, v2)
155+
if isEqual && err != nil {
156+
t.Errorf("Equal(%v, %v) = %v, want = nil", v1, v2, err)
157+
} else if !isEqual && err == nil {
158+
t.Errorf("Equal(%v, %v) = nil, want = error", v1, v2)
159+
}
160+
161+
err = Equal(assertion.T, v1, v2)
162+
if isEqual && err != nil {
163+
t.Errorf("Equal(%v, %v) = %v, want = nil", v1, v2, err)
164+
} else if !isEqual && err == nil {
165+
t.Errorf("Equal(%v, %v) = nil, want = error", v1, v2)
166+
}
167+
}
168+
169+
func testNotEqual(t *testing.T, assertion *Assertion, v1, v2 any, isEqual bool) {
170+
err := assertion.NotEqual(v1, v2)
171+
if isEqual && err == nil {
172+
t.Errorf("NotEqual(%v, %v) = nil, want = error", v1, v2)
173+
} else if !isEqual && err != nil {
174+
t.Errorf("NotEqual(%v, %v) = %v, want = nil", v1, v2, err)
175+
}
176+
177+
err = NotEqual(assertion.T, v1, v2)
178+
if isEqual && err == nil {
179+
t.Errorf("NotEqual(%v, %v) = nil, want = error", v1, v2)
180+
} else if !isEqual && err != nil {
181+
t.Errorf("NotEqual(%v, %v) = %v, want = nil", v1, v2, err)
182+
}
183+
}
184+
185+
func testEqualNow(t *testing.T, assertion *Assertion, v1, v2 any, isEqual bool) {
186+
isTerminated := internal.CheckTermination(func() {
187+
assertion.EqualNow(v1, v2)
188+
})
189+
if isEqual && isTerminated {
190+
t.Error("execution stopped, want do not stop")
191+
} else if !isEqual && !isTerminated {
192+
t.Error("execution do not stopped, want stop")
193+
}
194+
195+
isTerminated = internal.CheckTermination(func() {
196+
EqualNow(assertion.T, v1, v2)
197+
})
198+
if isEqual && isTerminated {
199+
t.Error("execution stopped, want do not stop")
200+
} else if !isEqual && !isTerminated {
201+
t.Error("execution do not stopped, want stop")
202+
}
203+
}
204+
205+
func testNotEqualNow(t *testing.T, assertion *Assertion, v1, v2 any, isEqual bool) {
206+
isTerminated := internal.CheckTermination(func() {
207+
assertion.NotEqualNow(v1, v2)
208+
})
209+
if !isEqual && isTerminated {
210+
t.Error("execution stopped, want do not stop")
211+
} else if isEqual && !isTerminated {
212+
t.Error("execution do not stopped, want stop")
213+
}
214+
215+
isTerminated = internal.CheckTermination(func() {
216+
NotEqualNow(assertion.T, v1, v2)
217+
})
218+
if !isEqual && isTerminated {
219+
t.Error("execution stopped, want do not stop")
220+
} else if isEqual && !isTerminated {
221+
t.Error("execution do not stopped, want stop")
222+
}
223+
}
224+
119225
func TestNilAndNotNil(t *testing.T) {
120226
mockT := new(testing.T)
121227
assert := New(mockT)

util.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,67 @@ func failed(t *testing.T, err error, failedNow bool) {
2626
// ## Assertion Helper Functions ##
2727
// ################################
2828

29+
// isEqual checks the equality of the values.
30+
func isEqual(x, y any) bool {
31+
if x == nil || y == nil {
32+
return x == y
33+
}
34+
v1 := reflect.ValueOf(x)
35+
v2 := reflect.ValueOf(y)
36+
if !isSameType(v1.Type(), v2.Type()) {
37+
return false
38+
}
39+
40+
switch v1.Kind() {
41+
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
42+
return v1.Int() == v2.Int()
43+
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
44+
return v1.Uint() == v2.Uint()
45+
case reflect.Float32, reflect.Float64:
46+
return v1.Float() == v2.Float()
47+
case reflect.Complex64, reflect.Complex128:
48+
return v1.Complex() == v2.Complex()
49+
case reflect.Slice:
50+
return isSliceEqual(v1, v2)
51+
default:
52+
return v1 == v2
53+
}
54+
}
55+
56+
// isSameType indicates the equality of two types, and it will ignore the bit size of the same
57+
// type. For example, `int32` and `int64` will be the same type.
58+
func isSameType(t1, t2 reflect.Type) bool {
59+
kind := t2.Kind()
60+
61+
switch t1.Kind() {
62+
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
63+
return kind >= reflect.Int && kind <= reflect.Int64
64+
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
65+
return kind >= reflect.Uint && kind <= reflect.Uint64
66+
case reflect.Float32, reflect.Float64:
67+
return kind == reflect.Float32 || kind == reflect.Float64
68+
case reflect.Complex64, reflect.Complex128:
69+
return kind == reflect.Complex64 || kind == reflect.Complex128
70+
default:
71+
return t1 == t2
72+
}
73+
}
74+
75+
// isSliceEqual checks the equality of each elements in the slices.
76+
func isSliceEqual(v1, v2 reflect.Value) bool {
77+
if v1.Len() != v2.Len() {
78+
return false
79+
}
80+
81+
for i := 0; i < v1.Len(); i++ {
82+
if v1.Index(i).Interface() != v2.Index(i).Interface() {
83+
return false
84+
}
85+
}
86+
87+
return true
88+
}
89+
2990
// isNil checks whether a value is nil or not. It'll always return false if the value is not a
3091
// channel, a function, a map, a point, an unsafe point, an interface, or a slice.
3192
func isNil(val any) bool {

util_test.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,62 @@ func TestFailedHandler(t *testing.T) {
2222
assert.DeepEqual(isTerminated, true)
2323
}
2424

25+
func TestIsEqual(t *testing.T) {
26+
assert := New(t)
27+
28+
type testStruct1 struct {
29+
A int
30+
}
31+
type testStruct2 struct {
32+
A int
33+
}
34+
35+
var s1 *testStruct1
36+
37+
assert.Equal(isEqual(nil, nil), true)
38+
assert.Equal(isEqual(nil, s1), false) // s1 is nil
39+
assert.Equal(isEqual(true, false), false)
40+
assert.Equal(isEqual(1, 1), true)
41+
assert.Equal(isEqual(1, 2), false)
42+
assert.Equal(isEqual(1, int64(1)), true)
43+
assert.Equal(isEqual(1, int64(2)), false)
44+
assert.Equal(isEqual(uint(1), uint(1)), true)
45+
assert.Equal(isEqual(uint(1), uint(2)), false)
46+
assert.Equal(isEqual(uint(1), uint64(1)), true)
47+
assert.Equal(isEqual(uint(1), uint64(2)), false)
48+
assert.Equal(isEqual(1.0, 1.0), true)
49+
assert.Equal(isEqual(1.0, 2.0), false)
50+
assert.Equal(isEqual(1.0, float32(1.0)), true)
51+
assert.Equal(isEqual(1.0, float32(2.0)), false)
52+
assert.Equal(isEqual(complex(1, 1), complex(1, 1)), true)
53+
assert.Equal(isEqual(complex(1, 1), complex(2, 2)), false)
54+
assert.Equal(isEqual(complex(1, 1), complex64(complex(1, 1))), true)
55+
assert.Equal(isEqual(complex(1, 1), complex64(complex(2, 2))), false)
56+
assert.Equal(isEqual([1]int{0}, [1]int{0}), true)
57+
assert.Equal(isEqual([1]int{0}, [1]int{1}), false)
58+
assert.Equal(isEqual([1]int{0}, [2]int{0, 0}), false)
59+
assert.Equal(isEqual([1]int{0}, [1]float64{0.0}), false)
60+
assert.Equal(isEqual("hello", "hello"), true)
61+
assert.Equal(isEqual("hello", "world"), false)
62+
63+
slice1 := []int{0}
64+
slice2 := []int{0}
65+
slice3 := []int{0, 0}
66+
slice4 := []int{1}
67+
slice5 := []float64{0.0}
68+
assert.Equal(isEqual(slice1, slice1), true)
69+
assert.Equal(isEqual(slice1, slice2), true)
70+
assert.Equal(isEqual(slice1, slice3), false)
71+
assert.Equal(isEqual(slice1, slice4), false)
72+
assert.Equal(isEqual(slice1, slice5), false)
73+
74+
assert.Equal(isEqual(testStruct1{A: 0}, testStruct1{A: 0}), true)
75+
assert.Equal(isEqual(testStruct1{A: 0}, testStruct1{A: 1}), false)
76+
assert.Equal(isEqual(s1, s1), true)
77+
assert.Equal(isEqual(&testStruct1{A: 0}, &testStruct1{A: 1}), false)
78+
assert.Equal(isEqual(testStruct1{A: 0}, testStruct2{A: 0}), false)
79+
}
80+
2581
func TestIsNil(t *testing.T) {
2682
assert := New(t)
2783

0 commit comments

Comments
 (0)