-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathadd-notifier_test.go
115 lines (98 loc) · 2.86 KB
/
add-notifier_test.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
/*
© 2022–present Harald Rudell <[email protected]> (https://haraldrudell.github.io/haraldrudell/)
ISC License
*/
package parl
import (
"context"
"slices"
"testing"
"github.com/haraldrudell/parl/perrors"
"github.com/haraldrudell/parl/pruntime"
)
func TestAddNotifier(t *testing.T) {
var countersCount = 4
var expCounters = []int{1, 0, 1, 1}
// check expCounters
if len(expCounters) != countersCount {
panic(perrors.NewPF("bad expcounters length"))
}
var ctx context.Context
var actCounters = make([]int, countersCount)
// get packFunc
var packFunc = notifierInvokeCancel(ctx)
// packFunc: parl.notifierInvokeCancel
t.Logf("packFunc: %s", packFunc)
// create counters
var counters = make([]*notifierCounter, countersCount)
for i := range counters {
counters[i] = newNotifierCounter(packFunc, t)
}
// create contexts ctx…ctx4
ctx = context.Background()
// counters[0] is notified of all context cancels
var ctx0 = AddNotifier(ctx, counters[0].notifierFunc)
// counters[1] is notified of context cancels in
// child contexts without a notifier1
// - ie. no cancelations
var ctx1 = AddNotifier1(ctx0, counters[1].notifierFunc)
// counters[2] is notified of context cancels in ctx2…
var ctx2 = AddNotifier1(ctx1, counters[2].notifierFunc)
// counters[3] is notified of all context cancels
var ctx3 = AddNotifier(ctx2, counters[3].notifierFunc)
// ctx4 is CancelContext
var ctx4 = NewCancelContext(ctx3)
// cancel a context
notifierInvokeCancel(ctx4)
// counter invocations should match expCounters
for i, c := range counters {
actCounters[i] = c.count
}
if !slices.Equal(actCounters, expCounters) {
t.Errorf("counters bad:\n%v exp:\n%v",
actCounters,
expCounters,
)
}
}
// notifierCounter is a fixture counting invocations
type notifierCounter struct {
count int
packFunc string
t *testing.T
}
// newNotifierCounter returns a notifier that counts its invocations
func newNotifierCounter(packFunc string, t *testing.T) (c *notifierCounter) {
return ¬ifierCounter{
packFunc: packFunc,
t: t,
}
}
// notifierFunc is a notifierFunc function for child or all contexts
func (c *notifierCounter) notifierFunc(stack Stack) {
t := c.t
// count invocation
c.count++
// check stack trace
var frames = stack.Frames()
if len(frames) < 2 {
panic(perrors.ErrorfPF("bad stack slice: %s"))
}
var tracePackFunc = frames[1].Loc().PackFunc()
if tracePackFunc == c.packFunc {
return // stack trace OK return
}
t.Logf("TRACE: %s", stack)
panic(perrors.New("Bad stack slice"))
}
// notifierInvokeCancel retrieves packFunc and invokes InvokeCancel
func notifierInvokeCancel(ctx context.Context) (packFunc string) {
if ctx != nil {
// if ctx present, cancel it
InvokeCancel(ctx)
} else {
// if ctx not present, return packFunc for cancellation stack trace
packFunc = pruntime.NewCodeLocation(0).PackFunc()
}
return
}