File: memoize_test.go

package info (click to toggle)
golang-golang-x-tools 1%3A0.1.0%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 12,588 kB
  • sloc: javascript: 2,011; asm: 1,458; sh: 174; yacc: 155; makefile: 21; ansic: 17
file content (107 lines) | stat: -rw-r--r-- 2,876 bytes parent folder | download
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
// Copyright 2019 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 memoize_test

import (
	"context"
	"strings"
	"testing"

	"golang.org/x/tools/internal/memoize"
)

func TestGet(t *testing.T) {
	s := &memoize.Store{}
	g := s.Generation("x")

	evaled := 0

	h := g.Bind("key", func(context.Context, memoize.Arg) interface{} {
		evaled++
		return "res"
	}, nil)
	expectGet(t, h, g, "res")
	expectGet(t, h, g, "res")
	if evaled != 1 {
		t.Errorf("got %v calls to function, wanted 1", evaled)
	}
}

func expectGet(t *testing.T, h *memoize.Handle, g *memoize.Generation, wantV interface{}) {
	t.Helper()
	gotV, gotErr := h.Get(context.Background(), g, nil)
	if gotV != wantV || gotErr != nil {
		t.Fatalf("Get() = %v, %v, wanted %v, nil", gotV, gotErr, wantV)
	}
}

func expectGetError(t *testing.T, h *memoize.Handle, g *memoize.Generation, substr string) {
	gotV, gotErr := h.Get(context.Background(), g, nil)
	if gotErr == nil || !strings.Contains(gotErr.Error(), substr) {
		t.Fatalf("Get() = %v, %v, wanted err %q", gotV, gotErr, substr)
	}
}

func TestGenerations(t *testing.T) {
	s := &memoize.Store{}
	// Evaluate key in g1.
	g1 := s.Generation("g1")
	h1 := g1.Bind("key", func(context.Context, memoize.Arg) interface{} { return "res" }, nil)
	expectGet(t, h1, g1, "res")

	// Get key in g2. It should inherit the value from g1.
	g2 := s.Generation("g2")
	h2 := g2.Bind("key", func(context.Context, memoize.Arg) interface{} {
		t.Fatal("h2 should not need evaluation")
		return "error"
	}, nil)
	expectGet(t, h2, g2, "res")

	// With g1 destroyed, g2 should still work.
	g1.Destroy()
	expectGet(t, h2, g2, "res")

	// With all generations destroyed, key should be re-evaluated.
	g2.Destroy()
	g3 := s.Generation("g3")
	h3 := g3.Bind("key", func(context.Context, memoize.Arg) interface{} { return "new res" }, nil)
	expectGet(t, h3, g3, "new res")
}

func TestCleanup(t *testing.T) {
	s := &memoize.Store{}
	g1 := s.Generation("g1")
	v1 := false
	v2 := false
	cleanup := func(v interface{}) {
		*(v.(*bool)) = true
	}
	h1 := g1.Bind("key1", func(context.Context, memoize.Arg) interface{} {
		return &v1
	}, nil)
	h2 := g1.Bind("key2", func(context.Context, memoize.Arg) interface{} {
		return &v2
	}, cleanup)
	expectGet(t, h1, g1, &v1)
	expectGet(t, h2, g1, &v2)
	g2 := s.Generation("g2")
	g2.Inherit(h1, h2)

	g1.Destroy()
	expectGet(t, h1, g2, &v1)
	expectGet(t, h2, g2, &v2)
	for k, v := range map[string]*bool{"key1": &v1, "key2": &v2} {
		if got, want := *v, false; got != want {
			t.Errorf("after destroying g1, bound value %q is cleaned up", k)
		}
	}
	g2.Destroy()
	if got, want := v1, false; got != want {
		t.Error("after destroying g2, v1 is cleaned up")
	}
	if got, want := v2, true; got != want {
		t.Error("after destroying g2, v2 is not cleaned up")
	}
}