-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathhooks.go
127 lines (109 loc) · 3.14 KB
/
hooks.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package testcase
import (
"runtime"
"sync"
"testing"
"go.llib.dev/testcase/internal/caller"
)
const hookWarning = `you cannot create spec hooks after you used describe/when/and/then,
unless you create a new spec with the previously mentioned calls`
type hook struct {
Block func(*T) func()
Frame runtime.Frame
}
type hookOnce struct {
Block func(testing.TB)
Frame runtime.Frame
DoOnce func(testing.TB)
}
// Before give you the ability to run a block before each test case.
// This is ideal for doing clean ahead before each test case.
// The received *testing.T object is the same as the Test block *testing.T object
// This hook applied to this scope and anything that is nested from here.
// All setup block is stackable.
func (spec *Spec) Before(beforeBlock func(t *T)) {
spec.H().Helper()
spec.Around(func(t *T) func() {
spec.H().Helper()
beforeBlock(t)
return func() {}
})
}
// After give you the ability to run a block after each test case.
// This is ideal for running cleanups.
// The received *testing.T object is the same as the Then block *testing.T object
// This hook applied to this scope and anything that is nested from here.
// All setup block is stackable.
func (spec *Spec) After(afterBlock func(t *T)) {
spec.H().Helper()
spec.Around(func(t *T) func() {
spec.H().Helper()
return func() {
spec.H().Helper()
afterBlock(t)
}
})
}
// Around give you the ability to create "Before" setup for each test case,
// with the additional ability that the returned function will be deferred to run after the Then block is done.
// This is ideal for setting up mocks, and then return the assertion request calls in the return func.
// This hook applied to this scope and anything that is nested from here.
// All setup block is stackable.
//
// Deprecated: use Spec.Before with T.Cleanup or Spec.Before with T.Defer instead
func (spec *Spec) Around(block func(*T) func()) {
spec.H().Helper()
frame, _ := caller.GetFrame()
spec.modify(func(spec *Spec) {
spec.H().Helper()
if spec.immutable {
spec.testingTB.Fatal(hookWarning)
}
spec.hooks.Around = append(spec.hooks.Around, hook{
Block: block,
Frame: frame,
})
})
}
// BeforeAll give you the ability to create a hook
// that runs only once before the test cases.
func (spec *Spec) BeforeAll(blk func(tb testing.TB)) {
spec.H().Helper()
frame, _ := caller.GetFrame()
spec.modify(func(spec *Spec) {
spec.H().Helper()
if spec.immutable {
spec.testingTB.Fatal(hookWarning)
}
var onCall sync.Once
var beforeAll = func(tb testing.TB) {
onCall.Do(func() { blk(tb) })
}
h := hookOnce{
DoOnce: beforeAll,
Block: blk,
Frame: frame,
}
spec.hooks.BeforeAll = append(spec.hooks.BeforeAll, h)
})
}
func (spec *Spec) AfterAll(blk func(tb testing.TB)) {
spec.H().Helper()
frame, _ := caller.GetFrame()
spec.modify(func(spec *Spec) {
spec.H().Helper()
if spec.immutable {
spec.testingTB.Fatal(hookWarning)
}
var onCall sync.Once
var beforeAll = func(tb testing.TB) {
onCall.Do(func() { blk(tb) })
}
h := hookOnce{
DoOnce: beforeAll,
Block: blk,
Frame: frame,
}
spec.hooks.AfterAll = append(spec.hooks.AfterAll, h)
})
}