1
2
3
4
5
6
7 package testutil
8
9 import (
10 "fmt"
11 "math/rand"
12
13 . "github.com/onsi/gomega"
14
15 "github.com/syndtr/goleveldb/leveldb/iterator"
16 )
17
18 type IterAct int
19
20 func (a IterAct) String() string {
21 switch a {
22 case IterNone:
23 return "none"
24 case IterFirst:
25 return "first"
26 case IterLast:
27 return "last"
28 case IterPrev:
29 return "prev"
30 case IterNext:
31 return "next"
32 case IterSeek:
33 return "seek"
34 case IterSOI:
35 return "soi"
36 case IterEOI:
37 return "eoi"
38 }
39 return "unknown"
40 }
41
42 const (
43 IterNone IterAct = iota
44 IterFirst
45 IterLast
46 IterPrev
47 IterNext
48 IterSeek
49 IterSOI
50 IterEOI
51 )
52
53 type IteratorTesting struct {
54 KeyValue
55 Iter iterator.Iterator
56 Rand *rand.Rand
57 PostFn func(t *IteratorTesting)
58 Pos int
59 Act, LastAct IterAct
60
61 once bool
62 }
63
64 func (t *IteratorTesting) init() {
65 if !t.once {
66 t.Pos = -1
67 t.once = true
68 }
69 }
70
71 func (t *IteratorTesting) post() {
72 if t.PostFn != nil {
73 t.PostFn(t)
74 }
75 }
76
77 func (t *IteratorTesting) setAct(act IterAct) {
78 t.LastAct, t.Act = t.Act, act
79 }
80
81 func (t *IteratorTesting) text() string {
82 return fmt.Sprintf("at pos %d and last action was <%v> -> <%v>", t.Pos, t.LastAct, t.Act)
83 }
84
85 func (t *IteratorTesting) Text() string {
86 return "IteratorTesting is " + t.text()
87 }
88
89 func (t *IteratorTesting) IsFirst() bool {
90 t.init()
91 return t.Len() > 0 && t.Pos == 0
92 }
93
94 func (t *IteratorTesting) IsLast() bool {
95 t.init()
96 return t.Len() > 0 && t.Pos == t.Len()-1
97 }
98
99 func (t *IteratorTesting) TestKV() {
100 t.init()
101 key, value := t.Index(t.Pos)
102 Expect(t.Iter.Key()).NotTo(BeNil())
103 Expect(t.Iter.Key()).Should(Equal(key), "Key is invalid, %s", t.text())
104 Expect(t.Iter.Value()).Should(Equal(value), "Value for key %q, %s", key, t.text())
105 }
106
107 func (t *IteratorTesting) First() {
108 t.init()
109 t.setAct(IterFirst)
110
111 ok := t.Iter.First()
112 Expect(t.Iter.Error()).ShouldNot(HaveOccurred())
113 if t.Len() > 0 {
114 t.Pos = 0
115 Expect(ok).Should(BeTrue(), t.Text())
116 t.TestKV()
117 } else {
118 t.Pos = -1
119 Expect(ok).ShouldNot(BeTrue(), t.Text())
120 }
121 t.post()
122 }
123
124 func (t *IteratorTesting) Last() {
125 t.init()
126 t.setAct(IterLast)
127
128 ok := t.Iter.Last()
129 Expect(t.Iter.Error()).ShouldNot(HaveOccurred())
130 if t.Len() > 0 {
131 t.Pos = t.Len() - 1
132 Expect(ok).Should(BeTrue(), t.Text())
133 t.TestKV()
134 } else {
135 t.Pos = 0
136 Expect(ok).ShouldNot(BeTrue(), t.Text())
137 }
138 t.post()
139 }
140
141 func (t *IteratorTesting) Next() {
142 t.init()
143 t.setAct(IterNext)
144
145 ok := t.Iter.Next()
146 Expect(t.Iter.Error()).ShouldNot(HaveOccurred())
147 if t.Pos < t.Len()-1 {
148 t.Pos++
149 Expect(ok).Should(BeTrue(), t.Text())
150 t.TestKV()
151 } else {
152 t.Pos = t.Len()
153 Expect(ok).ShouldNot(BeTrue(), t.Text())
154 }
155 t.post()
156 }
157
158 func (t *IteratorTesting) Prev() {
159 t.init()
160 t.setAct(IterPrev)
161
162 ok := t.Iter.Prev()
163 Expect(t.Iter.Error()).ShouldNot(HaveOccurred())
164 if t.Pos > 0 {
165 t.Pos--
166 Expect(ok).Should(BeTrue(), t.Text())
167 t.TestKV()
168 } else {
169 t.Pos = -1
170 Expect(ok).ShouldNot(BeTrue(), t.Text())
171 }
172 t.post()
173 }
174
175 func (t *IteratorTesting) Seek(i int) {
176 t.init()
177 t.setAct(IterSeek)
178
179 key, _ := t.Index(i)
180 oldKey, _ := t.IndexOrNil(t.Pos)
181
182 ok := t.Iter.Seek(key)
183 Expect(t.Iter.Error()).ShouldNot(HaveOccurred())
184 Expect(ok).Should(BeTrue(), fmt.Sprintf("Seek from key %q to %q, to pos %d, %s", oldKey, key, i, t.text()))
185
186 t.Pos = i
187 t.TestKV()
188 t.post()
189 }
190
191 func (t *IteratorTesting) SeekInexact(i int) {
192 t.init()
193 t.setAct(IterSeek)
194 var key0 []byte
195 key1, _ := t.Index(i)
196 if i > 0 {
197 key0, _ = t.Index(i - 1)
198 }
199 key := BytesSeparator(key0, key1)
200 oldKey, _ := t.IndexOrNil(t.Pos)
201
202 ok := t.Iter.Seek(key)
203 Expect(t.Iter.Error()).ShouldNot(HaveOccurred())
204 Expect(ok).Should(BeTrue(), fmt.Sprintf("Seek from key %q to %q (%q), to pos %d, %s", oldKey, key, key1, i, t.text()))
205
206 t.Pos = i
207 t.TestKV()
208 t.post()
209 }
210
211 func (t *IteratorTesting) SeekKey(key []byte) {
212 t.init()
213 t.setAct(IterSeek)
214 oldKey, _ := t.IndexOrNil(t.Pos)
215 i := t.Search(key)
216
217 ok := t.Iter.Seek(key)
218 Expect(t.Iter.Error()).ShouldNot(HaveOccurred())
219 if i < t.Len() {
220 key_, _ := t.Index(i)
221 Expect(ok).Should(BeTrue(), fmt.Sprintf("Seek from key %q to %q (%q), to pos %d, %s", oldKey, key, key_, i, t.text()))
222 t.Pos = i
223 t.TestKV()
224 } else {
225 Expect(ok).ShouldNot(BeTrue(), fmt.Sprintf("Seek from key %q to %q, %s", oldKey, key, t.text()))
226 }
227
228 t.Pos = i
229 t.post()
230 }
231
232 func (t *IteratorTesting) SOI() {
233 t.init()
234 t.setAct(IterSOI)
235 Expect(t.Pos).Should(BeNumerically("<=", 0), t.Text())
236 for i := 0; i < 3; i++ {
237 t.Prev()
238 }
239 t.post()
240 }
241
242 func (t *IteratorTesting) EOI() {
243 t.init()
244 t.setAct(IterEOI)
245 Expect(t.Pos).Should(BeNumerically(">=", t.Len()-1), t.Text())
246 for i := 0; i < 3; i++ {
247 t.Next()
248 }
249 t.post()
250 }
251
252 func (t *IteratorTesting) WalkPrev(fn func(t *IteratorTesting)) {
253 t.init()
254 for old := t.Pos; t.Pos > 0; old = t.Pos {
255 fn(t)
256 Expect(t.Pos).Should(BeNumerically("<", old), t.Text())
257 }
258 }
259
260 func (t *IteratorTesting) WalkNext(fn func(t *IteratorTesting)) {
261 t.init()
262 for old := t.Pos; t.Pos < t.Len()-1; old = t.Pos {
263 fn(t)
264 Expect(t.Pos).Should(BeNumerically(">", old), t.Text())
265 }
266 }
267
268 func (t *IteratorTesting) PrevAll() {
269 t.WalkPrev(func(t *IteratorTesting) {
270 t.Prev()
271 })
272 }
273
274 func (t *IteratorTesting) NextAll() {
275 t.WalkNext(func(t *IteratorTesting) {
276 t.Next()
277 })
278 }
279
280 func DoIteratorTesting(t *IteratorTesting) {
281 if t.Rand == nil {
282 t.Rand = NewRand()
283 }
284 t.SOI()
285 t.NextAll()
286 t.First()
287 t.SOI()
288 t.NextAll()
289 t.EOI()
290 t.PrevAll()
291 t.Last()
292 t.EOI()
293 t.PrevAll()
294 t.SOI()
295
296 t.NextAll()
297 t.PrevAll()
298 t.NextAll()
299 t.Last()
300 t.PrevAll()
301 t.First()
302 t.NextAll()
303 t.EOI()
304
305 ShuffledIndex(t.Rand, t.Len(), 1, func(i int) {
306 t.Seek(i)
307 })
308
309 ShuffledIndex(t.Rand, t.Len(), 1, func(i int) {
310 t.SeekInexact(i)
311 })
312
313 ShuffledIndex(t.Rand, t.Len(), 1, func(i int) {
314 t.Seek(i)
315 if i%2 != 0 {
316 t.PrevAll()
317 t.SOI()
318 } else {
319 t.NextAll()
320 t.EOI()
321 }
322 })
323
324 for _, key := range []string{"", "foo", "bar", "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"} {
325 t.SeekKey([]byte(key))
326 }
327 }
328
View as plain text