github.com/haraldrudell/parl@v0.4.176/add-notifier_test.go (about) 1 /* 2 © 2022–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/) 3 ISC License 4 */ 5 6 package parl 7 8 import ( 9 "context" 10 "slices" 11 "testing" 12 13 "github.com/haraldrudell/parl/perrors" 14 "github.com/haraldrudell/parl/pruntime" 15 ) 16 17 func TestAddNotifier(t *testing.T) { 18 var countersCount = 4 19 var expCounters = []int{1, 0, 1, 1} 20 21 // check expCounters 22 if len(expCounters) != countersCount { 23 panic(perrors.NewPF("bad expcounters length")) 24 } 25 26 var ctx context.Context 27 var actCounters = make([]int, countersCount) 28 29 // get packFunc 30 var packFunc = notifierInvokeCancel(ctx) 31 // packFunc: parl.notifierInvokeCancel 32 t.Logf("packFunc: %s", packFunc) 33 34 // create counters 35 var counters = make([]*notifierCounter, countersCount) 36 for i := range counters { 37 counters[i] = newNotifierCounter(packFunc, t) 38 } 39 40 // create contexts ctx…ctx4 41 ctx = context.Background() 42 // counters[0] is notified of all context cancels 43 var ctx0 = AddNotifier(ctx, counters[0].notifierFunc) 44 // counters[1] is notified of context cancels in 45 // child contexts without a notifier1 46 // - ie. no cancelations 47 var ctx1 = AddNotifier1(ctx0, counters[1].notifierFunc) 48 // counters[2] is notified of context cancels in ctx2… 49 var ctx2 = AddNotifier1(ctx1, counters[2].notifierFunc) 50 // counters[3] is notified of all context cancels 51 var ctx3 = AddNotifier(ctx2, counters[3].notifierFunc) 52 // ctx4 is CancelContext 53 var ctx4 = NewCancelContext(ctx3) 54 55 // cancel a context 56 notifierInvokeCancel(ctx4) 57 58 // counter invocations should match expCounters 59 for i, c := range counters { 60 actCounters[i] = c.count 61 } 62 if !slices.Equal(actCounters, expCounters) { 63 t.Errorf("counters bad:\n%v exp:\n%v", 64 actCounters, 65 expCounters, 66 ) 67 } 68 } 69 70 // notifierCounter is a fixture counting invocations 71 type notifierCounter struct { 72 count int 73 packFunc string 74 t *testing.T 75 } 76 77 // newNotifierCounter returns a notifier that counts its invocations 78 func newNotifierCounter(packFunc string, t *testing.T) (c *notifierCounter) { 79 return ¬ifierCounter{ 80 packFunc: packFunc, 81 t: t, 82 } 83 } 84 85 // notifierFunc is a notifierFunc function for child or all contexts 86 func (c *notifierCounter) notifierFunc(stack Stack) { 87 t := c.t 88 89 // count invocation 90 c.count++ 91 92 // check stack trace 93 var frames = stack.Frames() 94 if len(frames) < 2 { 95 panic(perrors.ErrorfPF("bad stack slice: %s")) 96 } 97 var tracePackFunc = frames[1].Loc().PackFunc() 98 if tracePackFunc == c.packFunc { 99 return // stack trace OK return 100 } 101 t.Logf("TRACE: %s", stack) 102 panic(perrors.New("Bad stack slice")) 103 } 104 105 // notifierInvokeCancel retrieves packFunc and invokes InvokeCancel 106 func notifierInvokeCancel(ctx context.Context) (packFunc string) { 107 if ctx != nil { 108 // if ctx present, cancel it 109 InvokeCancel(ctx) 110 } else { 111 // if ctx not present, return packFunc for cancellation stack trace 112 packFunc = pruntime.NewCodeLocation(0).PackFunc() 113 } 114 return 115 }