aboutsummaryrefslogtreecommitdiff
path: root/leaf_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'leaf_test.go')
-rw-r--r--leaf_test.go143
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)
+}