jldb/mdb/pfile/alloclist_test.go
2023-10-13 11:43:27 +02:00

173 lines
3.6 KiB
Go

package pfile
import (
"errors"
"reflect"
"testing"
)
func (al allocList) Assert(t *testing.T, state map[[2]uint64][]uint64) {
t.Helper()
if len(al) != len(state) {
t.Fatalf("Expected %d items, but found %d.", len(state), len(al))
}
for key, expected := range state {
val, ok := al[key]
if !ok {
t.Fatalf("Expected to find key %v.", key)
}
if !reflect.DeepEqual(val, expected) {
t.Fatalf("For %v, expected %v but got %v.", key, expected, val)
}
}
}
func (al *allocList) With(collectionID, itemID uint64, pages ...uint64) *allocList {
al.Store(collectionID, itemID, pages)
return al
}
func (al *allocList) Equals(rhs *allocList) bool {
if len(*rhs) != len(*al) {
return false
}
for key, val := range *rhs {
actual := (*al)[key]
if !reflect.DeepEqual(val, actual) {
return false
}
}
return true
}
func TestAllocList(t *testing.T) {
const (
CREATE = "CREATE"
PUSH = "PUSH"
STORE = "STORE"
REMOVE = "REMOVE"
)
type TestCase struct {
Name string
Action string
Key [2]uint64
Page uint64
Pages []uint64 // For STORE command.
Expected *allocList
ExpectedLen int
}
testCases := []TestCase{{
Name: "Create something",
Action: CREATE,
Key: [2]uint64{1, 1},
Page: 1,
Expected: newAllocList().With(1, 1, 1),
ExpectedLen: 1,
}, {
Name: "Push onto something",
Action: PUSH,
Key: [2]uint64{1, 1},
Page: 2,
Expected: newAllocList().With(1, 1, 1, 2),
ExpectedLen: 1,
}, {
Name: "Push onto something again",
Action: PUSH,
Key: [2]uint64{1, 1},
Page: 3,
Expected: newAllocList().With(1, 1, 1, 2, 3),
ExpectedLen: 1,
}, {
Name: "Store something",
Action: STORE,
Key: [2]uint64{2, 2},
Pages: []uint64{4, 5, 6},
Expected: newAllocList().With(1, 1, 1, 2, 3).With(2, 2, 4, 5, 6),
ExpectedLen: 2,
}, {
Name: "Remove something",
Action: REMOVE,
Key: [2]uint64{1, 1},
Expected: newAllocList().With(2, 2, 4, 5, 6),
ExpectedLen: 1,
}}
al := newAllocList()
for _, tc := range testCases {
switch tc.Action {
case CREATE:
al.Create(tc.Key[0], tc.Key[1], tc.Page)
case PUSH:
al.Push(tc.Key[0], tc.Key[1], tc.Page)
case STORE:
al.Store(tc.Key[0], tc.Key[1], tc.Pages)
case REMOVE:
al.Remove(tc.Key[0], tc.Key[1])
default:
t.Fatalf("Unknown action: %s", tc.Action)
}
if !al.Equals(tc.Expected) {
t.Fatal(tc.Name, al, tc.Expected)
}
if al.Len() != tc.ExpectedLen {
t.Fatal(tc.Name, al.Len(), tc.ExpectedLen)
}
}
}
func TestAllocListIterate_eachError(t *testing.T) {
al := newAllocList().With(1, 1, 2, 3, 4, 5)
myErr := errors.New("xxx")
err := al.Iterate(func(collectionID, itemID uint64, pageIDs []uint64) error {
return myErr
})
if err != myErr {
t.Fatal(err)
}
}
func TestAllocListIterate(t *testing.T) {
al := newAllocList().With(1, 1, 2, 3, 4, 5).With(2, 2, 6, 7)
expected := map[uint64][]uint64{
1: {2, 3, 4, 5},
2: {6, 7},
}
err := al.Iterate(func(collectionID, itemID uint64, pageIDs []uint64) error {
e, ok := expected[collectionID]
if !ok {
t.Fatalf("Not found: %d", collectionID)
}
if !reflect.DeepEqual(e, pageIDs) {
t.Fatalf("%v != %v", pageIDs, e)
}
return nil
})
if err != nil {
t.Fatal(err)
}
}
func TestAllocListPushNoHead(t *testing.T) {
al := newAllocList().With(1, 1, 2, 3, 4, 5).With(2, 2, 6, 7)
if !al.Push(1, 1, 8) {
t.Fatal("Failed to push onto head page")
}
if al.Push(1, 2, 9) {
t.Fatal("Pushed with no head.")
}
}