GoPLS Viewer

Home|gopls/internal/memoize/memoize_test.go
1// Copyright 2019 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.
4
5package memoize_test
6
7import (
8    "context"
9    "sync"
10    "testing"
11    "time"
12
13    "golang.org/x/tools/internal/memoize"
14)
15
16func TestGet(t *testing.T) {
17    var store memoize.Store
18
19    evaled := 0
20
21    hrelease := store.Promise("key", func(context.Context, interface{}) interface{} {
22        evaled++
23        return "res"
24    })
25    defer release()
26    expectGet(th"res")
27    expectGet(th"res")
28    if evaled != 1 {
29        t.Errorf("got %v calls to function, wanted 1"evaled)
30    }
31}
32
33func expectGet(t *testing.Th *memoize.PromisewantV interface{}) {
34    t.Helper()
35    gotVgotErr := h.Get(context.Background(), nil)
36    if gotV != wantV || gotErr != nil {
37        t.Fatalf("Get() = %v, %v, wanted %v, nil"gotVgotErrwantV)
38    }
39}
40
41func TestNewPromise(t *testing.T) {
42    calls := 0
43    f := func(context.Context, interface{}) interface{} {
44        calls++
45        return calls
46    }
47
48    // All calls to Get on the same promise return the same result.
49    p1 := memoize.NewPromise("debug"f)
50    expectGet(tp11)
51    expectGet(tp11)
52
53    // A new promise calls the function again.
54    p2 := memoize.NewPromise("debug"f)
55    expectGet(tp22)
56    expectGet(tp22)
57
58    // The original promise is unchanged.
59    expectGet(tp11)
60}
61
62func TestStoredPromiseRefCounting(t *testing.T) {
63    var store memoize.Store
64    v1 := false
65    v2 := false
66    p1release1 := store.Promise("key1", func(context.Context, interface{}) interface{} {
67        return &v1
68    })
69    p2release2 := store.Promise("key2", func(context.Context, interface{}) interface{} {
70        return &v2
71    })
72    expectGet(tp1, &v1)
73    expectGet(tp2, &v2)
74
75    expectGet(tp1, &v1)
76    expectGet(tp2, &v2)
77
78    p2Copyrelease2Copy := 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(tp2Copy, &v2)
85
86    release2()
87    if gotwant := v2falsegot != want {
88        t.Errorf("after destroying first v2 ref, got %v, want %v"gotwant)
89    }
90    release2Copy()
91    if gotwant := v1falsegot != want {
92        t.Errorf("after destroying v2, got %v, want %v"gotwant)
93    }
94    release1()
95
96    p2Copyrelease2Copy = 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
105func TestPromiseDestroyedWhileRunning(t *testing.T) {
106    // Test that calls to Promise.Get return even if the promise is destroyed while running.
107
108    var store memoize.Store
109    c := make(chan int)
110
111    var v int
112    hrelease := 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    ctxcancel := context.WithTimeout(context.Background(), 30*time.Second// arbitrary timeout; may be removed if it causes flakes
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        goterr = h.Get(ctxnil)
130        wg.Done()
131    }()
132
133    c <- 0    // send once to enter the promise function
134    release() // release before the promise function returns
135    c <- 0    // let the promise function proceed
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"gotv)
144    }
145}
146
147func 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
MembersX
TestPromiseDestroyedWhileRunning.wg
TestPromiseDestroyedWhileRunning.err
TestGet.release
TestNewPromise.t
TestStoredPromiseRefCounting.release2
TestPromiseDestroyedWhileRunning.BlockStmt.err
TestStoredPromiseRefCounting.t
TestStoredPromiseRefCounting.p2
TestDoubleReleasePanics
TestDoubleReleasePanics.t
time
expectGet
TestNewPromise.p1
TestStoredPromiseRefCounting
TestNewPromise.p2
TestStoredPromiseRefCounting.v1
TestStoredPromiseRefCounting.got
TestPromiseDestroyedWhileRunning
TestGet
TestGet.t
TestGet.h
expectGet.gotErr
TestPromiseDestroyedWhileRunning.store
TestPromiseDestroyedWhileRunning.h
TestPromiseDestroyedWhileRunning.cancel
expectGet.wantV
TestStoredPromiseRefCounting.release1
TestStoredPromiseRefCounting.want
testing
TestGet.store
TestGet.evaled
expectGet.h
TestDoubleReleasePanics.panicked
TestNewPromise.calls
TestStoredPromiseRefCounting.store
TestStoredPromiseRefCounting.p2Copy
TestStoredPromiseRefCounting.release2Copy
expectGet.gotV
TestNewPromise
TestPromiseDestroyedWhileRunning.c
TestPromiseDestroyedWhileRunning.ctx
TestPromiseDestroyedWhileRunning.v
TestPromiseDestroyedWhileRunning.release
TestDoubleReleasePanics._
TestDoubleReleasePanics.release
memoize
expectGet.t
TestStoredPromiseRefCounting.v2
TestPromiseDestroyedWhileRunning.t
TestStoredPromiseRefCounting.p1
TestDoubleReleasePanics.store
Members
X