1
2
3
4
5 package memoize_test
6
7 import (
8 "context"
9 "sync"
10 "testing"
11 "time"
12
13 "golang.org/x/tools/internal/memoize"
14 )
15
16 func TestGet(t *testing.T) {
17 var store memoize.Store
18
19 evaled := 0
20
21 h, release := store.Promise("key", func(context.Context, interface{}) interface{} {
22 evaled++
23 return "res"
24 })
25 defer release()
26 expectGet(t, h, "res")
27 expectGet(t, h, "res")
28 if evaled != 1 {
29 t.Errorf("got %v calls to function, wanted 1", evaled)
30 }
31 }
32
33 func expectGet(t *testing.T, h *memoize.Promise, wantV interface{}) {
34 t.Helper()
35 gotV, gotErr := h.Get(context.Background(), nil)
36 if gotV != wantV || gotErr != nil {
37 t.Fatalf("Get() = %v, %v, wanted %v, nil", gotV, gotErr, wantV)
38 }
39 }
40
41 func TestNewPromise(t *testing.T) {
42 calls := 0
43 f := func(context.Context, interface{}) interface{} {
44 calls++
45 return calls
46 }
47
48
49 p1 := memoize.NewPromise("debug", f)
50 expectGet(t, p1, 1)
51 expectGet(t, p1, 1)
52
53
54 p2 := memoize.NewPromise("debug", f)
55 expectGet(t, p2, 2)
56 expectGet(t, p2, 2)
57
58
59 expectGet(t, p1, 1)
60 }
61
62 func TestStoredPromiseRefCounting(t *testing.T) {
63 var store memoize.Store
64 v1 := false
65 v2 := false
66 p1, release1 := store.Promise("key1", func(context.Context, interface{}) interface{} {
67 return &v1
68 })
69 p2, release2 := store.Promise("key2", func(context.Context, interface{}) interface{} {
70 return &v2
71 })
72 expectGet(t, p1, &v1)
73 expectGet(t, p2, &v2)
74
75 expectGet(t, p1, &v1)
76 expectGet(t, p2, &v2)
77
78 p2Copy, release2Copy := store.Promise("key2", func(context.Context, interface{}) interface{} {
79 return &v1
80 })
81 if p2 != p2Copy {
82 t.Error("Promise returned a new value while old is not destroyed yet")
83 }
84 expectGet(t, p2Copy, &v2)
85
86 release2()
87 if got, want := v2, false; got != want {
88 t.Errorf("after destroying first v2 ref, got %v, want %v", got, want)
89 }
90 release2Copy()
91 if got, want := v1, false; got != want {
92 t.Errorf("after destroying v2, got %v, want %v", got, want)
93 }
94 release1()
95
96 p2Copy, release2Copy = store.Promise("key2", func(context.Context, interface{}) interface{} {
97 return &v2
98 })
99 if p2 == p2Copy {
100 t.Error("Promise returned previously destroyed value")
101 }
102 release2Copy()
103 }
104
105 func TestPromiseDestroyedWhileRunning(t *testing.T) {
106
107
108 var store memoize.Store
109 c := make(chan int)
110
111 var v int
112 h, release := store.Promise("key", func(ctx context.Context, _ interface{}) interface{} {
113 <-c
114 <-c
115 if err := ctx.Err(); err != nil {
116 t.Errorf("ctx.Err() = %v, want nil", err)
117 }
118 return &v
119 })
120
121 ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
122 defer cancel()
123
124 var wg sync.WaitGroup
125 wg.Add(1)
126 var got interface{}
127 var err error
128 go func() {
129 got, err = h.Get(ctx, nil)
130 wg.Done()
131 }()
132
133 c <- 0
134 release()
135 c <- 0
136
137 wg.Wait()
138
139 if err != nil {
140 t.Errorf("Get() failed: %v", err)
141 }
142 if got != &v {
143 t.Errorf("Get() = %v, want %v", got, v)
144 }
145 }
146
147 func TestDoubleReleasePanics(t *testing.T) {
148 var store memoize.Store
149 _, release := store.Promise("key", func(ctx context.Context, _ interface{}) interface{} { return 0 })
150
151 panicked := false
152
153 func() {
154 defer func() {
155 if recover() != nil {
156 panicked = true
157 }
158 }()
159 release()
160 release()
161 }()
162
163 if !panicked {
164 t.Errorf("calling release() twice did not panic")
165 }
166 }
167
View as plain text