github.com/Kintar/etxt@v0.0.0-20221224033739-2fc69f000137/ecache/cache_test.go (about)

     1  //go:build gtxt
     2  
     3  package ecache
     4  
     5  import "time"
     6  import "image"
     7  import "sync/atomic"
     8  
     9  import "testing"
    10  
    11  import "github.com/Kintar/etxt/emask"
    12  
    13  import "golang.org/x/image/math/fixed"
    14  
    15  func TestDefaultCache(t *testing.T) {
    16  	masks := make([]GlyphMask, 10)
    17  
    18  	rect := image.Rect(0, 0, 10, 10)
    19  	for i := 0; i < 10; i++ {
    20  		masks[i] = GlyphMask(image.NewAlpha(rect))
    21  		masks[i].Pix[i] = 1
    22  	}
    23  	refSize := GlyphMaskByteSize(masks[0])
    24  
    25  	cache, err := NewDefaultCache(int(refSize * 8))
    26  	if err != nil {
    27  		panic(err)
    28  	}
    29  
    30  	gotSize := cache.ApproxByteSize()
    31  	if gotSize != 0 {
    32  		t.Fatalf("expected %d, got %d", 0, gotSize)
    33  	}
    34  
    35  	gotSize = cache.PeakSize()
    36  	if gotSize != 0 {
    37  		t.Fatalf("expected %d, got %d", 0, gotSize)
    38  	}
    39  
    40  	mask, found := cache.GetMask([3]uint64{0, 0, 1})
    41  	if found {
    42  		t.Fatal("didn't expect to find mask")
    43  	}
    44  	if mask != nil {
    45  		t.Fatal("expected nil mask")
    46  	}
    47  
    48  	cache.PassMask([3]uint64{0, 0, 2}, masks[2])
    49  	_, found = cache.GetMask([3]uint64{0, 0, 1})
    50  	if found {
    51  		t.Fatal("didn't expect to find mask")
    52  	}
    53  
    54  	mask, found = cache.GetMask([3]uint64{0, 0, 2})
    55  	if !found {
    56  		t.Fatal("expected to find mask")
    57  	}
    58  	if mask.Pix[2] != 1 {
    59  		t.Fatal("absurd test")
    60  	}
    61  
    62  	for i := 3; i < 10; i++ {
    63  		if i <= 5 {
    64  			time.Sleep(200 * time.Millisecond)
    65  		} // keep mask additions appart
    66  		cache.PassMask([3]uint64{0, 0, uint64(i)}, masks[i])
    67  	}
    68  
    69  	for i := 3; i < 10; i++ {
    70  		mask, found = cache.GetMask([3]uint64{0, 0, uint64(i)})
    71  		if !found {
    72  			t.Fatal("expected to find mask")
    73  		}
    74  		if mask.Pix[i-1] != 0 || mask.Pix[i] != 1 {
    75  			t.Fatal("wrong mask")
    76  		}
    77  	}
    78  
    79  	gotSize = cache.ApproxByteSize()
    80  	expectSize := int(refSize) * 8
    81  	if gotSize != expectSize {
    82  		t.Fatalf("expected %d, got %d", expectSize, gotSize)
    83  	}
    84  	gotSize = cache.PeakSize()
    85  	if gotSize != expectSize {
    86  		t.Fatalf("expected %d, got %d", expectSize, gotSize)
    87  	}
    88  
    89  	time.Sleep(200 * time.Millisecond)
    90  	cache.PassMask([3]uint64{0, 0, 0}, masks[0])
    91  	mask, found = cache.GetMask([3]uint64{0, 0, 0})
    92  	if !found {
    93  		t.Fatal("expected mask to be added")
    94  	}
    95  
    96  	mask, found = cache.GetMask([3]uint64{0, 0, 2})
    97  	if found {
    98  		t.Fatal("expected mask to be evicted")
    99  	}
   100  
   101  	gotSize = cache.ApproxByteSize()
   102  	if gotSize != expectSize {
   103  		t.Fatalf("expected %d, got %d", expectSize, gotSize)
   104  	}
   105  	gotSize = cache.PeakSize()
   106  	if gotSize != expectSize {
   107  		t.Fatalf("expected %d, got %d", expectSize, gotSize)
   108  	}
   109  
   110  	for i := 3; i < 10; i++ {
   111  		mask, found = cache.GetMask([3]uint64{0, 0, uint64(i)})
   112  		if !found {
   113  			t.Fatal("expected to find mask")
   114  		}
   115  		if mask.Pix[i-1] != 0 || mask.Pix[i] != 1 {
   116  			t.Fatal("wrong mask")
   117  		}
   118  	}
   119  
   120  	// cooldown for recently accessed masks
   121  	time.Sleep(200 * time.Millisecond)
   122  
   123  	biggerMask := GlyphMask(image.NewAlpha(image.Rect(0, 0, 12, 12)))
   124  	cache.PassMask([3]uint64{999, 999, 999}, biggerMask)
   125  	_, found = cache.GetMask([3]uint64{0, 0, 3})
   126  	if found {
   127  		t.Fatal("expected mask to be evicted")
   128  	}
   129  	_, found = cache.GetMask([3]uint64{0, 0, 4})
   130  	if found {
   131  		t.Fatal("expected mask to be evicted")
   132  	}
   133  	_, found = cache.GetMask([3]uint64{0, 0, 1})
   134  	if found {
   135  		t.Fatal("this mask hasn't been ever passed to cache")
   136  	}
   137  	_, found = cache.GetMask([3]uint64{0, 0, 5})
   138  	if !found {
   139  		t.Fatal("expected mask to be present")
   140  	}
   141  	_, found = cache.GetMask([3]uint64{0, 0, 0})
   142  	if !found {
   143  		t.Fatal("expected mask to be present")
   144  	}
   145  
   146  	gotSize = cache.PeakSize()
   147  	if gotSize != expectSize {
   148  		t.Fatalf("expected %d, got %d", expectSize, gotSize)
   149  	}
   150  	expectSize = expectSize - int(refSize*2) + int(GlyphMaskByteSize(biggerMask))
   151  	gotSize = cache.ApproxByteSize()
   152  	if gotSize != expectSize {
   153  		t.Fatalf("expected %d, got %d", expectSize, gotSize)
   154  	}
   155  }
   156  
   157  func TestDefaultHandler(t *testing.T) {
   158  	cache, err := NewDefaultCache(16 * 1024 * 1024)
   159  	if err != nil {
   160  		panic(err)
   161  	}
   162  
   163  	rast := emask.DefaultRasterizer{}
   164  	rast.SetHighByte(0x77)
   165  
   166  	handler := cache.NewHandler()
   167  	handler.NotifyFontChange(nil)
   168  	handler.NotifyRasterizerChange(&rast)
   169  	handler.NotifySizeChange(12 << 6)
   170  	handler.NotifyFractChange(fixed.Point26_6{1, 1})
   171  
   172  	if handler.ApproxCacheByteSize() != 0 {
   173  		t.Fatal("no mask yet size != 0")
   174  	}
   175  
   176  	if GlyphMaskByteSize(nil) != constMaskSizeFactor {
   177  		t.Fatal("assumptions")
   178  	}
   179  
   180  	_, found := handler.GetMask(9)
   181  	if found {
   182  		t.Fatal("no mask in the cache")
   183  	}
   184  	handler.PassMask(9, nil)
   185  	mask, found := handler.GetMask(9)
   186  	if !found {
   187  		t.Fatal("expected mask in cache")
   188  	}
   189  	if mask != nil {
   190  		t.Fatal("expected nil mask")
   191  	}
   192  
   193  	gotSize := handler.PeakCacheSize()
   194  	if gotSize != constMaskSizeFactor {
   195  		t.Fatalf("expected %d bytes, got %d", constMaskSizeFactor, gotSize)
   196  	}
   197  
   198  	mask, found = cache.GetMask([3]uint64{0, 0x7700000000000000, 0x0000030000410009})
   199  	if !found {
   200  		t.Fatal("expected mask at the given key")
   201  	}
   202  	if mask != nil {
   203  		t.Fatal("expected nil mask")
   204  	}
   205  
   206  	freed := cache.removeRandEntry(100000, CacheEntryInstant())
   207  	if freed != constMaskSizeFactor {
   208  		t.Fatalf("expected %d freed bytes, got %d", constMaskSizeFactor, freed)
   209  	}
   210  	atomic.AddUint32(&cache.spaceBytesLeft, constMaskSizeFactor)
   211  
   212  	freed = cache.removeRandEntry(100000, CacheEntryInstant())
   213  	if freed != 0 {
   214  		t.Fatalf("expected 0 freed bytes, got %d", freed)
   215  	}
   216  
   217  	gotSize = handler.ApproxCacheByteSize()
   218  	if gotSize != 0 {
   219  		t.Fatalf("expected 0 bytes, got %d", gotSize)
   220  	}
   221  
   222  	gotSize = handler.PeakCacheSize()
   223  	if gotSize != constMaskSizeFactor {
   224  		t.Fatalf("expected %d bytes, got %d", constMaskSizeFactor, gotSize)
   225  	}
   226  }