github.com/jd-ly/tools@v0.5.7/internal/memoize/memoize_test.go (about) 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 5 package memoize_test 6 7 import ( 8 "context" 9 "strings" 10 "testing" 11 12 "github.com/jd-ly/tools/internal/memoize" 13 ) 14 15 func TestGet(t *testing.T) { 16 s := &memoize.Store{} 17 g := s.Generation("x") 18 19 evaled := 0 20 21 h := g.Bind("key", func(context.Context, memoize.Arg) interface{} { 22 evaled++ 23 return "res" 24 }, nil) 25 expectGet(t, h, g, "res") 26 expectGet(t, h, g, "res") 27 if evaled != 1 { 28 t.Errorf("got %v calls to function, wanted 1", evaled) 29 } 30 } 31 32 func expectGet(t *testing.T, h *memoize.Handle, g *memoize.Generation, wantV interface{}) { 33 t.Helper() 34 gotV, gotErr := h.Get(context.Background(), g, nil) 35 if gotV != wantV || gotErr != nil { 36 t.Fatalf("Get() = %v, %v, wanted %v, nil", gotV, gotErr, wantV) 37 } 38 } 39 40 func expectGetError(t *testing.T, h *memoize.Handle, g *memoize.Generation, substr string) { 41 gotV, gotErr := h.Get(context.Background(), g, nil) 42 if gotErr == nil || !strings.Contains(gotErr.Error(), substr) { 43 t.Fatalf("Get() = %v, %v, wanted err %q", gotV, gotErr, substr) 44 } 45 } 46 47 func TestGenerations(t *testing.T) { 48 s := &memoize.Store{} 49 // Evaluate key in g1. 50 g1 := s.Generation("g1") 51 h1 := g1.Bind("key", func(context.Context, memoize.Arg) interface{} { return "res" }, nil) 52 expectGet(t, h1, g1, "res") 53 54 // Get key in g2. It should inherit the value from g1. 55 g2 := s.Generation("g2") 56 h2 := g2.Bind("key", func(context.Context, memoize.Arg) interface{} { 57 t.Fatal("h2 should not need evaluation") 58 return "error" 59 }, nil) 60 expectGet(t, h2, g2, "res") 61 62 // With g1 destroyed, g2 should still work. 63 g1.Destroy() 64 expectGet(t, h2, g2, "res") 65 66 // With all generations destroyed, key should be re-evaluated. 67 g2.Destroy() 68 g3 := s.Generation("g3") 69 h3 := g3.Bind("key", func(context.Context, memoize.Arg) interface{} { return "new res" }, nil) 70 expectGet(t, h3, g3, "new res") 71 } 72 73 func TestCleanup(t *testing.T) { 74 s := &memoize.Store{} 75 g1 := s.Generation("g1") 76 v1 := false 77 v2 := false 78 cleanup := func(v interface{}) { 79 *(v.(*bool)) = true 80 } 81 h1 := g1.Bind("key1", func(context.Context, memoize.Arg) interface{} { 82 return &v1 83 }, nil) 84 h2 := g1.Bind("key2", func(context.Context, memoize.Arg) interface{} { 85 return &v2 86 }, cleanup) 87 expectGet(t, h1, g1, &v1) 88 expectGet(t, h2, g1, &v2) 89 g2 := s.Generation("g2") 90 g2.Inherit(h1, h2) 91 92 g1.Destroy() 93 expectGet(t, h1, g2, &v1) 94 expectGet(t, h2, g2, &v2) 95 for k, v := range map[string]*bool{"key1": &v1, "key2": &v2} { 96 if got, want := *v, false; got != want { 97 t.Errorf("after destroying g1, bound value %q is cleaned up", k) 98 } 99 } 100 g2.Destroy() 101 if got, want := v1, false; got != want { 102 t.Error("after destroying g2, v1 is cleaned up") 103 } 104 if got, want := v2, true; got != want { 105 t.Error("after destroying g2, v2 is not cleaned up") 106 } 107 }