Skip to content

Commit cc107cd

Browse files
authored
Assert tests (#33)
1 parent 5c32d7d commit cc107cd

3 files changed

Lines changed: 282 additions & 6 deletions

File tree

index.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ func (idx *index) bucketIndex(hash uint32) uint32 {
9898
return bidx
9999
}
100100

101+
// TODO: deeply nested callbacks are hard to reason about.
102+
// TODO: rewrite the function to return an iterator if there is no performance implications.
101103
func (idx *index) forEachBucket(startBucketIdx uint32, cb func(bucketHandle) (bool, error)) error {
102104
off := bucketOffset(startBucketIdx)
103105
f := idx.main.MmapFile

internal/assert/assert.go

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,28 +14,45 @@ func Equal(t testing.TB, expected interface{}, actual interface{}) {
1414
}
1515
}
1616

17-
// Nil fails the test when actual is not nil.
18-
func Nil(t testing.TB, actual interface{}) {
19-
if actual != nil && !reflect.ValueOf(actual).IsNil() {
17+
// https://github.com/golang/go/blob/go1.15/src/reflect/value.go#L1071
18+
var nillableKinds = map[reflect.Kind]bool{
19+
reflect.Chan: true,
20+
reflect.Func: true,
21+
reflect.Map: true,
22+
reflect.Ptr: true,
23+
reflect.UnsafePointer: true,
24+
reflect.Interface: true,
25+
reflect.Slice: true,
26+
}
27+
28+
// Nil fails the test when obj is not nil.
29+
func Nil(t testing.TB, obj interface{}) {
30+
if obj == nil {
31+
return
32+
}
33+
val := reflect.ValueOf(obj)
34+
if !nillableKinds[val.Kind()] || !val.IsNil() {
2035
t.Helper()
21-
t.Fatalf("expected nil; got %+v", actual)
36+
t.Fatalf("expected nil; got %+v", obj)
2237
}
2338
}
2439

40+
const pollingInterval = time.Millisecond * 10 // How often CompleteWithin polls the cond function.
41+
2542
// CompleteWithin fails the test when cond doesn't succeed within waitDur.
2643
func CompleteWithin(t testing.TB, waitDur time.Duration, cond func() bool) {
2744
start := time.Now()
2845
for time.Since(start) < waitDur {
2946
if cond() {
3047
return
3148
}
32-
time.Sleep(time.Millisecond * 10)
49+
time.Sleep(pollingInterval)
3350
}
3451
t.Helper()
3552
t.Fatalf("expected to complete within %v", waitDur)
3653
}
3754

38-
// Panic fails the test when the test doesn't panic.
55+
// Panic fails the test when the test doesn't panic with the expected message.
3956
func Panic(t testing.TB, expectedMessage string, f func()) {
4057
t.Helper()
4158
var message interface{}

internal/assert/assert_test.go

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
package assert
2+
3+
import (
4+
"fmt"
5+
"sync"
6+
"testing"
7+
"time"
8+
)
9+
10+
func TestEqual(t *testing.T) {
11+
testCases := []struct {
12+
first interface{}
13+
second interface{}
14+
expectedFailed bool
15+
}{
16+
{
17+
first: 1,
18+
second: 1,
19+
expectedFailed: false,
20+
},
21+
22+
{
23+
first: nil,
24+
second: nil,
25+
expectedFailed: false,
26+
},
27+
{
28+
first: "1",
29+
second: "1",
30+
expectedFailed: false,
31+
},
32+
{
33+
first: struct{}{},
34+
second: struct{}{},
35+
expectedFailed: false,
36+
},
37+
{
38+
first: struct{ x int }{x: 1},
39+
second: struct{ x int }{x: 1},
40+
expectedFailed: false,
41+
},
42+
{
43+
first: 1,
44+
second: 2,
45+
expectedFailed: true,
46+
},
47+
{
48+
first: 1,
49+
second: "1",
50+
expectedFailed: true,
51+
},
52+
{
53+
first: 1,
54+
second: 1.0,
55+
expectedFailed: true,
56+
},
57+
{
58+
first: struct{ x int }{x: 1},
59+
second: struct{ x int }{x: 2},
60+
expectedFailed: true,
61+
},
62+
{
63+
first: struct{ x int }{x: 1},
64+
second: struct{ y int }{y: 1},
65+
expectedFailed: true,
66+
},
67+
}
68+
69+
for i, tc := range testCases {
70+
t.Run(fmt.Sprintf("case %d %+v", i, tc), func(t *testing.T) {
71+
mock := &testing.T{}
72+
wg := &sync.WaitGroup{}
73+
wg.Add(1)
74+
// Run the asserting in a goroutine. t.Fatal calls runtime.Goexit.
75+
go func() {
76+
defer wg.Done()
77+
Equal(mock, tc.first, tc.second)
78+
}()
79+
wg.Wait()
80+
failed := mock.Failed()
81+
if tc.expectedFailed != failed {
82+
t.Fatalf("expected to fail: %t; failed: %t", tc.expectedFailed, failed)
83+
}
84+
})
85+
}
86+
}
87+
88+
func TestNil(t *testing.T) {
89+
var nilIntPtr *int
90+
var nilStructPtr *struct{ x int }
91+
var nilSlice []string
92+
93+
testCases := []struct {
94+
obj interface{}
95+
expectedFailed bool
96+
}{
97+
{
98+
obj: nil,
99+
expectedFailed: false,
100+
},
101+
{
102+
obj: nilIntPtr,
103+
expectedFailed: false,
104+
},
105+
{
106+
obj: nilStructPtr,
107+
expectedFailed: false,
108+
},
109+
{
110+
obj: nilSlice,
111+
expectedFailed: false,
112+
},
113+
{
114+
obj: 1,
115+
expectedFailed: true,
116+
},
117+
{
118+
obj: "1",
119+
expectedFailed: true,
120+
},
121+
{
122+
obj: []string{},
123+
expectedFailed: true,
124+
},
125+
{
126+
obj: [2]int{1, 1},
127+
expectedFailed: true,
128+
},
129+
}
130+
131+
for i, tc := range testCases {
132+
t.Run(fmt.Sprintf("case %d %+v", i, tc.obj), func(t *testing.T) {
133+
mock := &testing.T{}
134+
wg := &sync.WaitGroup{}
135+
wg.Add(1)
136+
go func() {
137+
defer wg.Done()
138+
Nil(mock, tc.obj)
139+
}()
140+
wg.Wait()
141+
if tc.expectedFailed != mock.Failed() {
142+
t.Fatalf("expected to fail: %t; failed: %t", tc.expectedFailed, mock.Failed())
143+
}
144+
})
145+
}
146+
}
147+
148+
func TestPanic(t *testing.T) {
149+
testCases := []struct {
150+
name string
151+
f func()
152+
expectedFailed bool
153+
}{
154+
{
155+
name: "panic",
156+
f: func() {
157+
panic("message123")
158+
},
159+
expectedFailed: false,
160+
},
161+
{
162+
name: "panic: wrong message",
163+
f: func() {
164+
panic("message456")
165+
},
166+
expectedFailed: true,
167+
},
168+
{
169+
name: "no panic",
170+
f: func() {},
171+
expectedFailed: true,
172+
},
173+
}
174+
for _, tc := range testCases {
175+
t.Run(tc.name, func(t *testing.T) {
176+
mock := &testing.T{}
177+
wg := &sync.WaitGroup{}
178+
wg.Add(1)
179+
go func() {
180+
defer wg.Done()
181+
Panic(mock, "message123", tc.f)
182+
}()
183+
wg.Wait()
184+
if tc.expectedFailed != mock.Failed() {
185+
t.Fatalf("expected to fail: %t; failed: %t", tc.expectedFailed, mock.Failed())
186+
}
187+
})
188+
}
189+
}
190+
191+
func TestCompleteWithin(t *testing.T) {
192+
var tc2Tries int
193+
var tc4Tries int
194+
testCases := []struct {
195+
name string
196+
dur time.Duration
197+
cond func() bool
198+
expectedFailed bool
199+
}{
200+
{
201+
name: "completed: first try",
202+
dur: time.Hour,
203+
cond: func() bool {
204+
return true
205+
},
206+
expectedFailed: false,
207+
},
208+
{
209+
name: "completed: second try",
210+
dur: time.Hour,
211+
cond: func() bool {
212+
if tc2Tries == 0 {
213+
tc2Tries++
214+
return false
215+
}
216+
return true
217+
},
218+
expectedFailed: false,
219+
},
220+
{
221+
name: "not completed",
222+
dur: time.Nanosecond,
223+
cond: func() bool {
224+
return false
225+
},
226+
expectedFailed: true,
227+
},
228+
{
229+
name: "not completed: timeout",
230+
dur: time.Nanosecond,
231+
cond: func() bool {
232+
if tc4Tries == 0 {
233+
tc4Tries++
234+
time.Sleep(pollingInterval * 2)
235+
return false
236+
}
237+
return true
238+
},
239+
expectedFailed: true,
240+
},
241+
}
242+
for _, tc := range testCases {
243+
t.Run(tc.name, func(t *testing.T) {
244+
mock := &testing.T{}
245+
wg := &sync.WaitGroup{}
246+
wg.Add(1)
247+
go func() {
248+
defer wg.Done()
249+
CompleteWithin(mock, tc.dur, tc.cond)
250+
}()
251+
wg.Wait()
252+
if tc.expectedFailed != mock.Failed() {
253+
t.Fatalf("expected to fail: %t; failed: %t", tc.expectedFailed, mock.Failed())
254+
}
255+
})
256+
}
257+
}

0 commit comments

Comments
 (0)