diff options
Diffstat (limited to 'leaf_test.go')
-rw-r--r-- | leaf_test.go | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/leaf_test.go b/leaf_test.go new file mode 100644 index 0000000..ad23074 --- /dev/null +++ b/leaf_test.go @@ -0,0 +1,143 @@ +package bolt + +import ( + "testing" + "unsafe" + + "github.com/stretchr/testify/assert" +) + +// Ensure that a temporary page can insert a key/value. +func TestLeafPut(t *testing.T) { + l := &leaf{items: make(leafItems, 0)} + l.put([]byte("baz"), []byte("2")) + l.put([]byte("foo"), []byte("0")) + l.put([]byte("bar"), []byte("1")) + l.put([]byte("foo"), []byte("3")) + assert.Equal(t, len(l.items), 3) + assert.Equal(t, l.items[0], leafItem{[]byte("bar"), []byte("1")}) + assert.Equal(t, l.items[1], leafItem{[]byte("baz"), []byte("2")}) + assert.Equal(t, l.items[2], leafItem{[]byte("foo"), []byte("3")}) +} + +// Ensure that a temporary page can deserialize from a page. +func TestLeafRead(t *testing.T) { + // Create a page. + var buf [4096]byte + page := (*page)(unsafe.Pointer(&buf[0])) + page.count = 2 + + // Insert 2 leaf items at the beginning. sizeof(lnode) == 16 + nodes := (*[3]lnode)(unsafe.Pointer(&page.ptr)) + nodes[0] = lnode{flags: 0, pos: 32, ksize: 3, vsize: 4} // pos = sizeof(lnode) * 2 + nodes[1] = lnode{flags: 0, pos: 23, ksize: 10, vsize: 3} // pos = sizeof(lnode) + 3 + 4 + + // Write data for the nodes at the end. + data := (*[4096]byte)(unsafe.Pointer(&nodes[2])) + copy(data[:], []byte("barfooz")) + copy(data[7:], []byte("helloworldbye")) + + // Deserialize page into a temporary page. + l := &leaf{} + l.read(page) + + // Check that there are two items with correct data. + assert.Equal(t, len(l.items), 2) + assert.Equal(t, l.items[0].key, []byte("bar")) + assert.Equal(t, l.items[0].value, []byte("fooz")) + assert.Equal(t, l.items[1].key, []byte("helloworld")) + assert.Equal(t, l.items[1].value, []byte("bye")) +} + +// Ensure that a temporary page can serialize itself. +func TestLeafWrite(t *testing.T) { + // Create a temp page. + l := &leaf{items: make(leafItems, 0)} + l.put([]byte("susy"), []byte("que")) + l.put([]byte("ricki"), []byte("lake")) + l.put([]byte("john"), []byte("johnson")) + + // Write it to a page. + var buf [4096]byte + allocate := func(size int) (*page, error) { + return (*page)(unsafe.Pointer(&buf[0])), nil + } + pages, err := l.write(4096, allocate) + assert.NoError(t, err) + + // Read the page back in. + l2 := &leaf{} + l2.read(pages[0]) + + // Check that the two pages are the same. + assert.Equal(t, len(l2.items), 3) + assert.Equal(t, l2.items[0].key, []byte("john")) + assert.Equal(t, l2.items[0].value, []byte("johnson")) + assert.Equal(t, l2.items[1].key, []byte("ricki")) + assert.Equal(t, l2.items[1].value, []byte("lake")) + assert.Equal(t, l2.items[2].key, []byte("susy")) + assert.Equal(t, l2.items[2].value, []byte("que")) +} + +// Ensure that an error that an allocation error during writing is returned. +func TestLeafWriteError(t *testing.T) { + // Create a temp page. + l := &leaf{items: make(leafItems, 0)} + l.put([]byte("susy"), []byte("que")) + + // Write it to a page. + exp := &Error{} + allocate := func(size int) (*page, error) { + return nil, exp + } + pages, err := l.write(4096, allocate) + assert.Nil(t, pages) + assert.Equal(t, err, exp) +} + +// Ensure that a temporary page can split into appropriate subgroups. +func TestLeafSplit(t *testing.T) { + // Create a temp page. + l := &leaf{items: make(leafItems, 0)} + l.put([]byte("00000001"), []byte("0123456701234567")) + l.put([]byte("00000002"), []byte("0123456701234567")) + l.put([]byte("00000003"), []byte("0123456701234567")) + l.put([]byte("00000004"), []byte("0123456701234567")) + l.put([]byte("00000005"), []byte("0123456701234567")) + + // Split between 3 & 4. + groups := l.split(100) + + assert.Equal(t, len(groups), 2) + assert.Equal(t, len(groups[0]), 2) + assert.Equal(t, len(groups[1]), 3) +} + +// Ensure that a temporary page with the minimum number of items just returns a single split group. +func TestLeafSplitWithMinKeys(t *testing.T) { + // Create a temp page. + l := &leaf{items: make(leafItems, 0)} + l.put([]byte("00000001"), []byte("0123456701234567")) + l.put([]byte("00000002"), []byte("0123456701234567")) + + // Split. + groups := l.split(20) + assert.Equal(t, len(groups), 1) + assert.Equal(t, len(groups[0]), 2) +} + +// Ensure that a temporary page that has keys that all fit on a page just returns one split group. +func TestLeafSplitFitsInPage(t *testing.T) { + // Create a temp page. + l := &leaf{items: make(leafItems, 0)} + l.put([]byte("00000001"), []byte("0123456701234567")) + l.put([]byte("00000002"), []byte("0123456701234567")) + l.put([]byte("00000003"), []byte("0123456701234567")) + l.put([]byte("00000004"), []byte("0123456701234567")) + l.put([]byte("00000005"), []byte("0123456701234567")) + + // Split. + groups := l.split(4096) + assert.Equal(t, len(groups), 1) + assert.Equal(t, len(groups[0]), 5) +} |