// Copyright (c) 2014, Suryandaru Triandana // 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))) }