| // 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 key %q", key) |
| Expect(rkey).Should(Equal(key), "Key") |
| Expect(rvalue).Should(Equal(value), "Value for key %q", key) |
| |
| // Using inexact key. |
| rkey, rvalue, err = db.TestFind(key_) |
| Expect(err).ShouldNot(HaveOccurred(), "Error for key %q (%q)", key_, key) |
| Expect(rkey).Should(Equal(key)) |
| Expect(rvalue).Should(Equal(value), "Value for 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 |
| }, 3.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 |
| }, 50.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 |
| }, 50.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", Test(KeyValue_Generate(nil, 120, 1, 50, 10, 120))) |
| } |