Skip to content

Commit

Permalink
Improve test of lru package
Browse files Browse the repository at this point in the history
  • Loading branch information
motoki317 committed May 3, 2022
1 parent bdf1753 commit 289adfa
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 59 deletions.
10 changes: 0 additions & 10 deletions lru/internal/interface.go

This file was deleted.

4 changes: 2 additions & 2 deletions lru/internal/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func (e *Element[T]) Prev() *Element[T] {
}

// List implements a generic linked list based off of container/list. This
// contains the minimimum functionally required for an lru cache.
// contains the minimum functionally required for an LRU cache.
type List[T any] struct {
root Element[T]
len int
Expand All @@ -38,7 +38,7 @@ func NewList[T any]() *List[T] {
return l
}

// Init intializes the list with no elements.
// Init initializes the list with no elements.
func (l *List[T]) Init() {
l.root = Element[T]{}
l.root.prev = &l.root
Expand Down
80 changes: 70 additions & 10 deletions lru/internal/list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,43 @@ import (
"github.com/stretchr/testify/require"
)

func TestPushRemove(t *testing.T) {
func TestElement_Next(t *testing.T) {
t.Run("none", func(t *testing.T) {
ll := internal.NewList[int]()

e := ll.PushFront(1)

require.Nil(t, e.Next())
})
t.Run("next", func(t *testing.T) {
ll := internal.NewList[int]()

e1 := ll.PushFront(1)
e2 := ll.PushFront(2)

require.Equal(t, e1, e2.Next())
})
}

func TestElement_Prev(t *testing.T) {
t.Run("none", func(t *testing.T) {
ll := internal.NewList[int]()

e := ll.PushFront(1)

require.Nil(t, e.Prev())
})
t.Run("next", func(t *testing.T) {
ll := internal.NewList[int]()

e1 := ll.PushFront(1)
e2 := ll.PushFront(2)

require.Equal(t, e2, e1.Prev())
})
}

func TestList_PushRemove(t *testing.T) {
ll := internal.NewList[int]()
length := 10

Expand All @@ -17,20 +53,44 @@ func TestPushRemove(t *testing.T) {
require.Equal(t, ll.Len(), i)
}

for i := length; i <= 1; i++ {
for i := length; i >= 1; i-- {
ll.Remove(ll.Back())
require.Equal(t, ll.Len(), i)
require.Equal(t, ll.Len(), i-1)
}
}

func TestMoveToFront(t *testing.T) {
ll := internal.NewList[int]()
e := ll.PushFront(0)
ll.PushFront(1)
require.Equal(t, e, ll.Back())
func TestList_MoveToFront(t *testing.T) {
t.Run("single", func(t *testing.T) {
ll := internal.NewList[int]()
e := ll.PushFront(0)
require.Equal(t, e, ll.Back())

ll.MoveToFront(e)
require.Equal(t, e, ll.Back())
})
t.Run("multiple", func(t *testing.T) {
ll := internal.NewList[int]()
e := ll.PushFront(0)
ll.PushFront(1)
require.Equal(t, e, ll.Back())

ll.MoveToFront(e)
require.NotEqual(t, e, ll.Back())
})
}

ll.MoveToFront(e)
require.NotEqual(t, e, ll.Back())
func TestList_Back(t *testing.T) {
t.Run("empty", func(t *testing.T) {
ll := internal.NewList[int]()
e := ll.Back()
require.Nil(t, e)
})
t.Run("not empty", func(t *testing.T) {
ll := internal.NewList[int]()
e := ll.PushFront(1)
ll.PushFront(2)
require.Equal(t, e, ll.Back())
})
}

func TestInit(t *testing.T) {
Expand Down
2 changes: 0 additions & 2 deletions lru/lru.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import (
"github.com/motoki317/sc/lru/internal"
)

var _ internal.LRU[int, int] = &Cache[int, int]{}

// Cache is a lru cache. It automatically removes elements as new elements are
// added if the capacity is reached. Items are removes based on how recently
// they were used where the oldest items are removed first.
Expand Down
147 changes: 112 additions & 35 deletions lru/lru_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,67 +10,144 @@ import (

func TestCapacity(t *testing.T) {
tests := []struct {
name string
capacity int
}{
{1},
{10},
{100},
{"1", 1},
{"10", 10},
{"100", 100},
}

lru.New[int, int](lru.WithCapacity(10))
for _, tc := range tests {
lru := lru.New[int, int](lru.WithCapacity(tc.capacity))
for i := 0; i < tc.capacity+1; i++ {
lru.Set(i, i)
}
t.Run(tc.name, func(t *testing.T) {
lru := lru.New[int, int](lru.WithCapacity(tc.capacity))
for i := 0; i < tc.capacity+1; i++ {
lru.Set(i, i)
}

require.Equal(t, tc.capacity, lru.Len(), "expected capacity to be full")
require.Equal(t, tc.capacity, lru.Len(), "expected capacity to be full")

_, ok := lru.Get(0)
require.False(t, ok, "expected key to be evicted")
_, ok := lru.Get(0)
require.False(t, ok, "expected key to be evicted")

_, ok = lru.Get(1)
require.True(t, ok, "expected key to exist")
_, ok = lru.Get(1)
require.True(t, ok, "expected key to exist")
})
}
}

func TestGetMissing(t *testing.T) {
lru := lru.New[int, int]()
_, ok := lru.Get(0)
require.False(t, ok, "expected not ok")
func TestGet(t *testing.T) {
t.Run("missing", func(t *testing.T) {
lru := lru.New[int, int]()

_, ok := lru.Get(0)

require.False(t, ok, "expected not ok")
})
t.Run("existing", func(t *testing.T) {
lru := lru.New[int, int]()
value := 100

lru.Set(1, value)
actual, ok := lru.Get(1)

require.True(t, ok, "expected ok")
require.Equal(t, value, actual, "expected set value to be %s", value)
})
}

func TestSetGet(t *testing.T) {
lru := lru.New[int, int]()
value := 100
func TestPeek(t *testing.T) {
t.Run("missing", func(t *testing.T) {
lru := lru.New[int, int]()

_, ok := lru.Peek(1)

require.False(t, ok, "expected not ok")
})
t.Run("existing", func(t *testing.T) {
lru := lru.New[int, int]()

lru.Set(1, 1)
value, ok := lru.Peek(1)

require.True(t, ok, "expected ok")
require.Equal(t, 1, value, "expected peek value to be 1")
})
}

func TestSet(t *testing.T) {
t.Run("missing", func(t *testing.T) {
lru := lru.New[int, int]()

lru.Set(1, 1)
value, ok := lru.Get(1)

lru.Set(1, value)
value, ok := lru.Get(1)
require.True(t, ok, "expected ok")
require.Equal(t, 1, value, "expected set value to be 1")
})
t.Run("existing", func(t *testing.T) {
lru := lru.New[int, int]()

require.True(t, ok, "expected ok")
require.Equal(t, value, value, "expected set value %s", value)
lru.Set(1, 1)
lru.Set(1, 2)
value, ok := lru.Get(1)

require.True(t, ok, "expected ok")
require.Equal(t, 2, value, "expected set value to be2")
})
}

func TestDelete(t *testing.T) {
lru := lru.New[int, int]()
t.Run("missing", func(t *testing.T) {
lru := lru.New[int, int]()

key, value := 1, 100
lru.Set(key, value)
require.Equal(t, lru.Len(), 1)
key := 100
ok := lru.Delete(key)

require.False(t, ok, "expected not ok")
})
t.Run("existing", func(t *testing.T) {
lru := lru.New[int, int]()

ok := lru.Delete(key)
require.True(t, ok, "expected ok")
key, value := 1, 100
lru.Set(key, value)
require.Equal(t, lru.Len(), 1)

ok := lru.Delete(key)
require.True(t, ok, "expected ok")
})
}

func TestDeleteMissing(t *testing.T) {
lru := lru.New[int, int]()
key := 100
ok := lru.Delete(key)
require.False(t, ok, "expected not ok")
func TestDeleteOldest(t *testing.T) {
t.Run("missing", func(t *testing.T) {
lru := lru.New[int, int]()

_, _, ok := lru.DeleteOldest()

require.False(t, ok, "expected not ok")
})
t.Run("existing", func(t *testing.T) {
lru := lru.New[int, int]()

lru.Set(1, 10)
lru.Set(2, 20)
lru.Set(3, 30)

_, _ = lru.Get(1)
_, _ = lru.Get(2)
_, _ = lru.Get(3)

key, value, ok := lru.DeleteOldest()

require.True(t, ok, "expected ok")
require.Equal(t, 1, key, "expected key to be 1")
require.Equal(t, 10, value, "expected value to be 10")
})
}

func TestFlush(t *testing.T) {
lru := lru.New[int, int]()

key, value := 1, 100
lru.Set(key, value)
require.Equal(t, lru.Len(), 1)
Expand Down

0 comments on commit 289adfa

Please sign in to comment.