1 // Copyright 2023 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
14 // afterFuncContext is a context that's not one of the types
15 // defined in context.go, that supports registering AfterFuncs.
16 type afterFuncContext struct {
18 afterFuncs map[*byte]func()
23 func newAfterFuncContext() context.Context {
24 return &afterFuncContext{}
27 func (c *afterFuncContext) Deadline() (time.Time, bool) {
28 return time.Time{}, false
31 func (c *afterFuncContext) Done() <-chan struct{} {
35 c.done = make(chan struct{})
40 func (c *afterFuncContext) Err() error {
46 func (c *afterFuncContext) Value(key any) any {
50 func (c *afterFuncContext) AfterFunc(f func()) func() bool {
54 if c.afterFuncs == nil {
55 c.afterFuncs = make(map[*byte]func())
61 _, ok := c.afterFuncs[k]
62 delete(c.afterFuncs, k)
67 func (c *afterFuncContext) cancel(err error) {
74 for _, f := range c.afterFuncs {
80 func TestCustomContextAfterFuncCancel(t *testing.T) {
81 ctx0 := &afterFuncContext{}
82 ctx1, cancel := context.WithCancel(ctx0)
84 ctx0.cancel(context.Canceled)
88 func TestCustomContextAfterFuncTimeout(t *testing.T) {
89 ctx0 := &afterFuncContext{}
90 ctx1, cancel := context.WithTimeout(ctx0, veryLongDuration)
92 ctx0.cancel(context.Canceled)
96 func TestCustomContextAfterFuncAfterFunc(t *testing.T) {
97 ctx0 := &afterFuncContext{}
98 donec := make(chan struct{})
99 stop := context.AfterFunc(ctx0, func() {
103 ctx0.cancel(context.Canceled)
107 func TestCustomContextAfterFuncUnregisterCancel(t *testing.T) {
108 ctx0 := &afterFuncContext{}
109 _, cancel1 := context.WithCancel(ctx0)
110 _, cancel2 := context.WithCancel(ctx0)
111 if got, want := len(ctx0.afterFuncs), 2; got != want {
112 t.Errorf("after WithCancel(ctx0): ctx0 has %v afterFuncs, want %v", got, want)
116 if got, want := len(ctx0.afterFuncs), 0; got != want {
117 t.Errorf("after canceling WithCancel(ctx0): ctx0 has %v afterFuncs, want %v", got, want)
121 func TestCustomContextAfterFuncUnregisterTimeout(t *testing.T) {
122 ctx0 := &afterFuncContext{}
123 _, cancel := context.WithTimeout(ctx0, veryLongDuration)
124 if got, want := len(ctx0.afterFuncs), 1; got != want {
125 t.Errorf("after WithTimeout(ctx0, d): ctx0 has %v afterFuncs, want %v", got, want)
128 if got, want := len(ctx0.afterFuncs), 0; got != want {
129 t.Errorf("after canceling WithTimeout(ctx0, d): ctx0 has %v afterFuncs, want %v", got, want)
133 func TestCustomContextAfterFuncUnregisterAfterFunc(t *testing.T) {
134 ctx0 := &afterFuncContext{}
135 stop := context.AfterFunc(ctx0, func() {})
136 if got, want := len(ctx0.afterFuncs), 1; got != want {
137 t.Errorf("after AfterFunc(ctx0, f): ctx0 has %v afterFuncs, want %v", got, want)
140 if got, want := len(ctx0.afterFuncs), 0; got != want {
141 t.Errorf("after stopping AfterFunc(ctx0, f): ctx0 has %v afterFuncs, want %v", got, want)