| // Copyright (c) 2014, Suryandaru Triandana <syndtr@gmail.com> |
| // All rights reserved. |
| // |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| package table |
| |
| import ( |
| "encoding/binary" |
| "fmt" |
| |
| . "github.com/onsi/ginkgo" |
| . "github.com/onsi/gomega" |
| |
| "github.com/syndtr/goleveldb/leveldb/comparer" |
| "github.com/syndtr/goleveldb/leveldb/iterator" |
| "github.com/syndtr/goleveldb/leveldb/testutil" |
| "github.com/syndtr/goleveldb/leveldb/util" |
| ) |
| |
| type blockTesting struct { |
| tr *Reader |
| b *block |
| } |
| |
| func (t *blockTesting) TestNewIterator(slice *util.Range) iterator.Iterator { |
| return t.tr.newBlockIter(t.b, nil, slice, false) |
| } |
| |
| var _ = testutil.Defer(func() { |
| Describe("Block", func() { |
| Build := func(kv *testutil.KeyValue, restartInterval int) *blockTesting { |
| // Building the block. |
| bw := &blockWriter{ |
| restartInterval: restartInterval, |
| scratch: make([]byte, 30), |
| } |
| kv.Iterate(func(i int, key, value []byte) { |
| bw.append(key, value) |
| }) |
| bw.finish() |
| |
| // Opening the block. |
| data := bw.buf.Bytes() |
| restartsLen := int(binary.LittleEndian.Uint32(data[len(data)-4:])) |
| return &blockTesting{ |
| tr: &Reader{cmp: comparer.DefaultComparer}, |
| b: &block{ |
| data: data, |
| restartsLen: restartsLen, |
| restartsOffset: len(data) - (restartsLen+1)*4, |
| }, |
| } |
| } |
| |
| Describe("read test", func() { |
| for restartInterval := 1; restartInterval <= 5; restartInterval++ { |
| Describe(fmt.Sprintf("with restart interval of %d", restartInterval), func() { |
| kv := &testutil.KeyValue{} |
| Text := func() string { |
| return fmt.Sprintf("and %d keys", kv.Len()) |
| } |
| |
| Test := func() { |
| // Make block. |
| br := Build(kv, restartInterval) |
| // Do testing. |
| testutil.KeyValueTesting(nil, kv.Clone(), br, nil, nil) |
| } |
| |
| Describe(Text(), Test) |
| |
| kv.PutString("", "empty") |
| Describe(Text(), Test) |
| |
| kv.PutString("a1", "foo") |
| Describe(Text(), Test) |
| |
| kv.PutString("a2", "v") |
| Describe(Text(), Test) |
| |
| kv.PutString("a3qqwrkks", "hello") |
| Describe(Text(), Test) |
| |
| kv.PutString("a4", "bar") |
| Describe(Text(), Test) |
| |
| kv.PutString("a5111111", "v5") |
| kv.PutString("a6", "") |
| kv.PutString("a7", "v7") |
| kv.PutString("a8", "vvvvvvvvvvvvvvvvvvvvvv8") |
| kv.PutString("b", "v9") |
| kv.PutString("c9", "v9") |
| kv.PutString("c91", "v9") |
| kv.PutString("d0", "v9") |
| Describe(Text(), Test) |
| }) |
| } |
| }) |
| |
| Describe("out-of-bound slice test", func() { |
| kv := &testutil.KeyValue{} |
| kv.PutString("k1", "v1") |
| kv.PutString("k2", "v2") |
| kv.PutString("k3abcdefgg", "v3") |
| kv.PutString("k4", "v4") |
| kv.PutString("k5", "v5") |
| for restartInterval := 1; restartInterval <= 5; restartInterval++ { |
| Describe(fmt.Sprintf("with restart interval of %d", restartInterval), func() { |
| // Make block. |
| bt := Build(kv, restartInterval) |
| |
| Test := func(r *util.Range) func(done Done) { |
| return func(done Done) { |
| iter := bt.TestNewIterator(r) |
| Expect(iter.Error()).ShouldNot(HaveOccurred()) |
| |
| t := testutil.IteratorTesting{ |
| KeyValue: kv.Clone(), |
| Iter: iter, |
| } |
| |
| testutil.DoIteratorTesting(&t) |
| iter.Release() |
| done <- true |
| } |
| } |
| |
| It("Should do iterations and seeks correctly #0", |
| Test(&util.Range{Start: []byte("k0"), Limit: []byte("k6")}), 2.0) |
| |
| It("Should do iterations and seeks correctly #1", |
| Test(&util.Range{Start: []byte(""), Limit: []byte("zzzzzzz")}), 2.0) |
| }) |
| } |
| }) |
| }) |
| }) |