aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/sync/oncefunc_test.go
blob: 0273b894a9d823cdd4e8b428f1f872751fadece4 (plain)
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package sync_test

import (
	"sync"
	"testing"
)

// We assume that the Once.Do tests have already covered parallelism.

func TestOnceFunc(t *testing.T) {
	calls := 0
	f := sync.OnceFunc(func() { calls++ })
	allocs := testing.AllocsPerRun(10, f)
	if calls != 1 {
		t.Errorf("want calls==1, got %d", calls)
	}
	if allocs != 0 {
		t.Errorf("want 0 allocations per call, got %v", allocs)
	}
}

func TestOnceValue(t *testing.T) {
	calls := 0
	f := sync.OnceValue(func() int {
		calls++
		return calls
	})
	allocs := testing.AllocsPerRun(10, func() { f() })
	value := f()
	if calls != 1 {
		t.Errorf("want calls==1, got %d", calls)
	}
	if value != 1 {
		t.Errorf("want value==1, got %d", value)
	}
	if allocs != 0 {
		t.Errorf("want 0 allocations per call, got %v", allocs)
	}
}

func TestOnceValues(t *testing.T) {
	calls := 0
	f := sync.OnceValues(func() (int, int) {
		calls++
		return calls, calls + 1
	})
	allocs := testing.AllocsPerRun(10, func() { f() })
	v1, v2 := f()
	if calls != 1 {
		t.Errorf("want calls==1, got %d", calls)
	}
	if v1 != 1 || v2 != 2 {
		t.Errorf("want v1==1 and v2==2, got %d and %d", v1, v2)
	}
	if allocs != 0 {
		t.Errorf("want 0 allocations per call, got %v", allocs)
	}
}

// TODO: need to implement more complete panic handling for these tests.
// func testOncePanicX(t *testing.T, calls *int, f func()) {
// 	testOncePanicWith(t, calls, f, func(label string, p any) {
// 		if p != "x" {
// 			t.Fatalf("%s: want panic %v, got %v", label, "x", p)
// 		}
// 	})
// }

// func testOncePanicWith(t *testing.T, calls *int, f func(), check func(label string, p any)) {
// 	// Check that the each call to f panics with the same value, but the
// 	// underlying function is only called once.
// 	for _, label := range []string{"first time", "second time"} {
// 		var p any
// 		panicked := true
// 		func() {
// 			defer func() {
// 				p = recover()
// 			}()
// 			f()
// 			panicked = false
// 		}()
// 		if !panicked {
// 			t.Fatalf("%s: f did not panic", label)
// 		}
// 		check(label, p)
// 	}
// 	if *calls != 1 {
// 		t.Errorf("want calls==1, got %d", *calls)
// 	}
// }

// func TestOnceFuncPanic(t *testing.T) {
// 	calls := 0
// 	f := sync.OnceFunc(func() {
// 		calls++
// 		panic("x")
// 	})
// 	testOncePanicX(t, &calls, f)
// }

// func TestOnceValuePanic(t *testing.T) {
// 	calls := 0
// 	f := sync.OnceValue(func() int {
// 		calls++
// 		panic("x")
// 	})
// 	testOncePanicX(t, &calls, func() { f() })
// }

// func TestOnceValuesPanic(t *testing.T) {
// 	calls := 0
// 	f := sync.OnceValues(func() (int, int) {
// 		calls++
// 		panic("x")
// 	})
// 	testOncePanicX(t, &calls, func() { f() })
// }
//
// func TestOnceFuncPanicNil(t *testing.T) {
// 	calls := 0
// 	f := sync.OnceFunc(func() {
// 		calls++
// 		panic(nil)
// 	})
// 	testOncePanicWith(t, &calls, f, func(label string, p any) {
// 		switch p.(type) {
// 		case nil, *runtime.PanicNilError:
// 			return
// 		}
// 		t.Fatalf("%s: want nil panic, got %v", label, p)
// 	})
// }
//
// func TestOnceFuncGoexit(t *testing.T) {
// 	// If f calls Goexit, the results are unspecified. But check that f doesn't
// 	// get called twice.
// 	calls := 0
// 	f := sync.OnceFunc(func() {
// 		calls++
// 		runtime.Goexit()
// 	})
// 	var wg sync.WaitGroup
// 	for i := 0; i < 2; i++ {
// 		wg.Add(1)
// 		go func() {
// 			defer wg.Done()
// 			defer func() { recover() }()
// 			f()
// 		}()
// 		wg.Wait()
// 	}
// 	if calls != 1 {
// 		t.Errorf("want calls==1, got %d", calls)
// 	}
// }