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  }