// 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 testutil
|
|
|
|
import (
|
|
"fmt"
|
|
"math/rand"
|
|
|
|
. "github.com/onsi/ginkgo"
|
|
. "github.com/onsi/gomega"
|
|
|
|
"github.com/syndtr/goleveldb/leveldb/errors"
|
|
"github.com/syndtr/goleveldb/leveldb/util"
|
|
)
|
|
|
|
func TestFind(db Find, kv KeyValue) {
|
|
ShuffledIndex(nil, kv.Len(), 1, func(i int) {
|
|
key_, key, value := kv.IndexInexact(i)
|
|
|
|
// Using exact key.
|
|
rkey, rvalue, err := db.TestFind(key)
|
|
Expect(err).ShouldNot(HaveOccurred(), "Error for exact key %q", key)
|
|
Expect(rkey).Should(Equal(key), "Key")
|
|
Expect(rvalue).Should(Equal(value), "Value for exact key %q", key)
|
|
|
|
// Using inexact key.
|
|
rkey, rvalue, err = db.TestFind(key_)
|
|
Expect(err).ShouldNot(HaveOccurred(), "Error for inexact key %q (%q)", key_, key)
|
|
Expect(rkey).Should(Equal(key), "Key for inexact key %q (%q)", key_, key)
|
|
Expect(rvalue).Should(Equal(value), "Value for inexact key %q (%q)", key_, key)
|
|
})
|
|
}
|
|
|
|
func TestFindAfterLast(db Find, kv KeyValue) {
|
|
var key []byte
|
|
if kv.Len() > 0 {
|
|
key_, _ := kv.Index(kv.Len() - 1)
|
|
key = BytesAfter(key_)
|
|
}
|
|
rkey, _, err := db.TestFind(key)
|
|
Expect(err).Should(HaveOccurred(), "Find for key %q yield key %q", key, rkey)
|
|
Expect(err).Should(Equal(errors.ErrNotFound))
|
|
}
|
|
|
|
func TestGet(db Get, kv KeyValue) {
|
|
ShuffledIndex(nil, kv.Len(), 1, func(i int) {
|
|
key_, key, value := kv.IndexInexact(i)
|
|
|
|
// Using exact key.
|
|
rvalue, err := db.TestGet(key)
|
|
Expect(err).ShouldNot(HaveOccurred(), "Error for key %q", key)
|
|
Expect(rvalue).Should(Equal(value), "Value for key %q", key)
|
|
|
|
// Using inexact key.
|
|
if len(key_) > 0 {
|
|
_, err = db.TestGet(key_)
|
|
Expect(err).Should(HaveOccurred(), "Error for key %q", key_)
|
|
Expect(err).Should(Equal(errors.ErrNotFound))
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestHas(db Has, kv KeyValue) {
|
|
ShuffledIndex(nil, kv.Len(), 1, func(i int) {
|
|
key_, key, _ := kv.IndexInexact(i)
|
|
|
|
// Using exact key.
|
|
ret, err := db.TestHas(key)
|
|
Expect(err).ShouldNot(HaveOccurred(), "Error for key %q", key)
|
|
Expect(ret).Should(BeTrue(), "False for key %q", key)
|
|
|
|
// Using inexact key.
|
|
if len(key_) > 0 {
|
|
ret, err = db.TestHas(key_)
|
|
Expect(err).ShouldNot(HaveOccurred(), "Error for key %q", key_)
|
|
Expect(ret).ShouldNot(BeTrue(), "True for key %q", key)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestIter(db NewIterator, r *util.Range, kv KeyValue) {
|
|
iter := db.TestNewIterator(r)
|
|
Expect(iter.Error()).ShouldNot(HaveOccurred())
|
|
|
|
t := IteratorTesting{
|
|
KeyValue: kv,
|
|
Iter: iter,
|
|
}
|
|
|
|
DoIteratorTesting(&t)
|
|
iter.Release()
|
|
}
|
|
|
|
func KeyValueTesting(rnd *rand.Rand, kv KeyValue, p DB, setup func(KeyValue) DB, teardown func(DB)) {
|
|
if rnd == nil {
|
|
rnd = NewRand()
|
|
}
|
|
|
|
if p == nil {
|
|
BeforeEach(func() {
|
|
p = setup(kv)
|
|
})
|
|
if teardown != nil {
|
|
AfterEach(func() {
|
|
teardown(p)
|
|
})
|
|
}
|
|
}
|
|
|
|
It("Should find all keys with Find", func() {
|
|
if db, ok := p.(Find); ok {
|
|
TestFind(db, kv)
|
|
}
|
|
})
|
|
|
|
It("Should return error if Find on key after the last", func() {
|
|
if db, ok := p.(Find); ok {
|
|
TestFindAfterLast(db, kv)
|
|
}
|
|
})
|
|
|
|
It("Should only find exact key with Get", func() {
|
|
if db, ok := p.(Get); ok {
|
|
TestGet(db, kv)
|
|
}
|
|
})
|
|
|
|
It("Should only find present key with Has", func() {
|
|
if db, ok := p.(Has); ok {
|
|
TestHas(db, kv)
|
|
}
|
|
})
|
|
|
|
It("Should iterates and seeks correctly", func(done Done) {
|
|
if db, ok := p.(NewIterator); ok {
|
|
TestIter(db, nil, kv.Clone())
|
|
}
|
|
done <- true
|
|
}, 30.0)
|
|
|
|
It("Should iterates and seeks slice correctly", func(done Done) {
|
|
if db, ok := p.(NewIterator); ok {
|
|
RandomIndex(rnd, kv.Len(), Min(kv.Len(), 50), func(i int) {
|
|
type slice struct {
|
|
r *util.Range
|
|
start, limit int
|
|
}
|
|
|
|
key_, _, _ := kv.IndexInexact(i)
|
|
for _, x := range []slice{
|
|
{&util.Range{Start: key_, Limit: nil}, i, kv.Len()},
|
|
{&util.Range{Start: nil, Limit: key_}, 0, i},
|
|
} {
|
|
By(fmt.Sprintf("Random index of %d .. %d", x.start, x.limit), func() {
|
|
TestIter(db, x.r, kv.Slice(x.start, x.limit))
|
|
})
|
|
}
|
|
})
|
|
}
|
|
done <- true
|
|
}, 200.0)
|
|
|
|
It("Should iterates and seeks slice correctly", func(done Done) {
|
|
if db, ok := p.(NewIterator); ok {
|
|
RandomRange(rnd, kv.Len(), Min(kv.Len(), 50), func(start, limit int) {
|
|
By(fmt.Sprintf("Random range of %d .. %d", start, limit), func() {
|
|
r := kv.Range(start, limit)
|
|
TestIter(db, &r, kv.Slice(start, limit))
|
|
})
|
|
})
|
|
}
|
|
done <- true
|
|
}, 200.0)
|
|
}
|
|
|
|
func AllKeyValueTesting(rnd *rand.Rand, body, setup func(KeyValue) DB, teardown func(DB)) {
|
|
Test := func(kv *KeyValue) func() {
|
|
return func() {
|
|
var p DB
|
|
if setup != nil {
|
|
Defer("setup", func() {
|
|
p = setup(*kv)
|
|
})
|
|
}
|
|
if teardown != nil {
|
|
Defer("teardown", func() {
|
|
teardown(p)
|
|
})
|
|
}
|
|
if body != nil {
|
|
p = body(*kv)
|
|
}
|
|
KeyValueTesting(rnd, *kv, p, func(KeyValue) DB {
|
|
return p
|
|
}, nil)
|
|
}
|
|
}
|
|
|
|
Describe("with no key/value (empty)", Test(&KeyValue{}))
|
|
Describe("with empty key", Test(KeyValue_EmptyKey()))
|
|
Describe("with empty value", Test(KeyValue_EmptyValue()))
|
|
Describe("with one key/value", Test(KeyValue_OneKeyValue()))
|
|
Describe("with big value", Test(KeyValue_BigValue()))
|
|
Describe("with special key", Test(KeyValue_SpecialKey()))
|
|
Describe("with multiple key/value", Test(KeyValue_MultipleKeyValue()))
|
|
Describe("with generated key/value 2-incr", Test(KeyValue_Generate(nil, 120, 2, 1, 50, 10, 120)))
|
|
Describe("with generated key/value 3-incr", Test(KeyValue_Generate(nil, 120, 3, 1, 50, 10, 120)))
|
|
}
|