1// Copyright (c) 2014, Suryandaru Triandana <syndtr@gmail.com>
2// All rights reserved.
3//
4// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6
7package testutil
8
9import (
10	"fmt"
11	"math/rand"
12
13	. "github.com/onsi/ginkgo"
14	. "github.com/onsi/gomega"
15
16	"github.com/syndtr/goleveldb/leveldb/errors"
17	"github.com/syndtr/goleveldb/leveldb/util"
18)
19
20func TestFind(db Find, kv KeyValue) {
21	ShuffledIndex(nil, kv.Len(), 1, func(i int) {
22		key_, key, value := kv.IndexInexact(i)
23
24		// Using exact key.
25		rkey, rvalue, err := db.TestFind(key)
26		Expect(err).ShouldNot(HaveOccurred(), "Error for exact key %q", key)
27		Expect(rkey).Should(Equal(key), "Key")
28		Expect(rvalue).Should(Equal(value), "Value for exact key %q", key)
29
30		// Using inexact key.
31		rkey, rvalue, err = db.TestFind(key_)
32		Expect(err).ShouldNot(HaveOccurred(), "Error for inexact key %q (%q)", key_, key)
33		Expect(rkey).Should(Equal(key), "Key for inexact key %q (%q)", key_, key)
34		Expect(rvalue).Should(Equal(value), "Value for inexact key %q (%q)", key_, key)
35	})
36}
37
38func TestFindAfterLast(db Find, kv KeyValue) {
39	var key []byte
40	if kv.Len() > 0 {
41		key_, _ := kv.Index(kv.Len() - 1)
42		key = BytesAfter(key_)
43	}
44	rkey, _, err := db.TestFind(key)
45	Expect(err).Should(HaveOccurred(), "Find for key %q yield key %q", key, rkey)
46	Expect(err).Should(Equal(errors.ErrNotFound))
47}
48
49func TestGet(db Get, kv KeyValue) {
50	ShuffledIndex(nil, kv.Len(), 1, func(i int) {
51		key_, key, value := kv.IndexInexact(i)
52
53		// Using exact key.
54		rvalue, err := db.TestGet(key)
55		Expect(err).ShouldNot(HaveOccurred(), "Error for key %q", key)
56		Expect(rvalue).Should(Equal(value), "Value for key %q", key)
57
58		// Using inexact key.
59		if len(key_) > 0 {
60			_, err = db.TestGet(key_)
61			Expect(err).Should(HaveOccurred(), "Error for key %q", key_)
62			Expect(err).Should(Equal(errors.ErrNotFound))
63		}
64	})
65}
66
67func TestHas(db Has, kv KeyValue) {
68	ShuffledIndex(nil, kv.Len(), 1, func(i int) {
69		key_, key, _ := kv.IndexInexact(i)
70
71		// Using exact key.
72		ret, err := db.TestHas(key)
73		Expect(err).ShouldNot(HaveOccurred(), "Error for key %q", key)
74		Expect(ret).Should(BeTrue(), "False for key %q", key)
75
76		// Using inexact key.
77		if len(key_) > 0 {
78			ret, err = db.TestHas(key_)
79			Expect(err).ShouldNot(HaveOccurred(), "Error for key %q", key_)
80			Expect(ret).ShouldNot(BeTrue(), "True for key %q", key)
81		}
82	})
83}
84
85func TestIter(db NewIterator, r *util.Range, kv KeyValue) {
86	iter := db.TestNewIterator(r)
87	Expect(iter.Error()).ShouldNot(HaveOccurred())
88
89	t := IteratorTesting{
90		KeyValue: kv,
91		Iter:     iter,
92	}
93
94	DoIteratorTesting(&t)
95	iter.Release()
96}
97
98func KeyValueTesting(rnd *rand.Rand, kv KeyValue, p DB, setup func(KeyValue) DB, teardown func(DB)) {
99	if rnd == nil {
100		rnd = NewRand()
101	}
102
103	if p == nil {
104		BeforeEach(func() {
105			p = setup(kv)
106		})
107		if teardown != nil {
108			AfterEach(func() {
109				teardown(p)
110			})
111		}
112	}
113
114	It("Should find all keys with Find", func() {
115		if db, ok := p.(Find); ok {
116			TestFind(db, kv)
117		}
118	})
119
120	It("Should return error if Find on key after the last", func() {
121		if db, ok := p.(Find); ok {
122			TestFindAfterLast(db, kv)
123		}
124	})
125
126	It("Should only find exact key with Get", func() {
127		if db, ok := p.(Get); ok {
128			TestGet(db, kv)
129		}
130	})
131
132	It("Should only find present key with Has", func() {
133		if db, ok := p.(Has); ok {
134			TestHas(db, kv)
135		}
136	})
137
138	It("Should iterates and seeks correctly", func(done Done) {
139		if db, ok := p.(NewIterator); ok {
140			TestIter(db, nil, kv.Clone())
141		}
142		done <- true
143	}, 30.0)
144
145	It("Should iterates and seeks slice correctly", func(done Done) {
146		if db, ok := p.(NewIterator); ok {
147			RandomIndex(rnd, kv.Len(), Min(kv.Len(), 50), func(i int) {
148				type slice struct {
149					r            *util.Range
150					start, limit int
151				}
152
153				key_, _, _ := kv.IndexInexact(i)
154				for _, x := range []slice{
155					{&util.Range{Start: key_, Limit: nil}, i, kv.Len()},
156					{&util.Range{Start: nil, Limit: key_}, 0, i},
157				} {
158					By(fmt.Sprintf("Random index of %d .. %d", x.start, x.limit), func() {
159						TestIter(db, x.r, kv.Slice(x.start, x.limit))
160					})
161				}
162			})
163		}
164		done <- true
165	}, 200.0)
166
167	It("Should iterates and seeks slice correctly", func(done Done) {
168		if db, ok := p.(NewIterator); ok {
169			RandomRange(rnd, kv.Len(), Min(kv.Len(), 50), func(start, limit int) {
170				By(fmt.Sprintf("Random range of %d .. %d", start, limit), func() {
171					r := kv.Range(start, limit)
172					TestIter(db, &r, kv.Slice(start, limit))
173				})
174			})
175		}
176		done <- true
177	}, 200.0)
178}
179
180func AllKeyValueTesting(rnd *rand.Rand, body, setup func(KeyValue) DB, teardown func(DB)) {
181	Test := func(kv *KeyValue) func() {
182		return func() {
183			var p DB
184			if setup != nil {
185				Defer("setup", func() {
186					p = setup(*kv)
187				})
188			}
189			if teardown != nil {
190				Defer("teardown", func() {
191					teardown(p)
192				})
193			}
194			if body != nil {
195				p = body(*kv)
196			}
197			KeyValueTesting(rnd, *kv, p, func(KeyValue) DB {
198				return p
199			}, nil)
200		}
201	}
202
203	Describe("with no key/value (empty)", Test(&KeyValue{}))
204	Describe("with empty key", Test(KeyValue_EmptyKey()))
205	Describe("with empty value", Test(KeyValue_EmptyValue()))
206	Describe("with one key/value", Test(KeyValue_OneKeyValue()))
207	Describe("with big value", Test(KeyValue_BigValue()))
208	Describe("with special key", Test(KeyValue_SpecialKey()))
209	Describe("with multiple key/value", Test(KeyValue_MultipleKeyValue()))
210	Describe("with generated key/value 2-incr", Test(KeyValue_Generate(nil, 120, 2, 1, 50, 10, 120)))
211	Describe("with generated key/value 3-incr", Test(KeyValue_Generate(nil, 120, 3, 1, 50, 10, 120)))
212}
213