-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcollection_tester.go
192 lines (158 loc) · 4.74 KB
/
collection_tester.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
package ezdb
import (
"fmt"
"math/rand"
"slices"
"sort"
)
// CollectionTester is a convenience type to help build out collection testing with less boilerplate.
type CollectionTester[T any] struct {
C Collection[T]
Cmp func(a, b T) error // Comparison function to assert equivalence between two documents.
Data map[string]T // Test data.
}
func (t *CollectionTester[T]) DeleteAll() error {
if err := t.C.DeleteAll(); err != nil {
return fmt.Errorf("failed to delete all documents: %v", err)
}
return nil
}
// DeleteOne tests that the collection safely deletes a single document.
// The document is not reinserted after deletion.
func (t *CollectionTester[T]) DeleteOne() error {
// Select a random key.
// This selects from the collection rather than test data to allow the function to be reused, so long as the collection has one document
keys := t.C.GetAllKeys()
if len(keys) == 0 {
return fmt.Errorf("no documents")
}
n := rand.Intn(len(keys) - 1)
key := keys[n]
if err := t.C.Delete(key); err != nil {
return fmt.Errorf("failed to delete document '%s': %v", key, err)
}
// Confirm document has been deleted
has, err := t.C.Has(key)
if err != nil {
return fmt.Errorf("failed to test whether collection has deleted document '%s': %v", key, err)
} else if has {
return fmt.Errorf("expected collection not to have deleted document '%s'", key)
}
return nil
}
// Get tests that the collection retrieves all documents.
// The collection must be initialised.
func (t *CollectionTester[T]) Get() error {
errs := Errors{}
for key, data := range t.Data {
actual, err := t.C.Get(key)
if err != nil {
errs = append(errs, fmt.Errorf("failed to get document '%s': %v", key, err))
} else if err := t.Cmp(data, actual); err != nil {
errs = append(errs, fmt.Errorf("comparison failed for document '%s': %v", key, err))
}
}
return errs.Resolve()
}
func (t *CollectionTester[T]) GetAll() error {
all, err := t.C.GetAll()
if err != nil {
return fmt.Errorf("failed to get all documents: %v", err)
}
errs := Errors{}
for key, actual := range all {
expected := t.Data[key]
if err := t.Cmp(expected, actual); err != nil {
errs = append(errs, fmt.Errorf("comparison failed for document '%s': %v", key, err))
}
}
return errs.Resolve()
}
// Has tests that the collection has all documents.
// The collection must be initialised.
func (t *CollectionTester[T]) Has() error {
errs := Errors{}
for key := range t.Data {
has, err := t.C.Has(key)
if err != nil {
return fmt.Errorf("failed to test whether collection has document '%s': %v", key, err)
} else if !has {
errs = append(errs, fmt.Errorf("expected collection to have document '%s'", key))
}
}
return errs.Resolve()
}
// Init tests that the collection is correctly initialised.
// This opens the collection, deletes any existing data, and reinserts the test data.
func (t *CollectionTester[T]) Init() error {
fs := []func() error{t.Open, t.DeleteAll, t.Put}
for _, f := range fs {
if err := f(); err != nil {
return err
}
}
return nil
}
// IterCount tests that the iterator counts documents correctly.
// The collection must be initialised.
func (t *CollectionTester[T]) IterCount() error {
iter := t.C.Iter()
actual := iter.Count()
iter.Release()
expected := len(t.Data)
if expected != actual {
return fmt.Errorf("incorrect document count (expected %d, got %d)", expected, actual)
}
return nil
}
// IterSortKeys tests that the iterator sorts correctly by key.
// The collection must be initialised.
func (t *CollectionTester[T]) IterSortKeys() error {
ks := &keySort{
a: []string{},
f: func(a, b string) bool {
return a < b
},
}
for key := range t.Data {
ks.a = append(ks.a, key)
}
sort.Stable(ks)
sortedKeys := ks.Result()
iter := t.C.Iter().SortKeys(ks.f)
defer iter.Release()
errs := Errors{}
actual := 0
for iter.Next() {
key := iter.Key()
if key != sortedKeys[actual] {
expected := slices.Index(sortedKeys, key)
errs = append(errs, fmt.Errorf("incorrect sort position of key '%s' (expected %d, got %d)", key, expected, actual))
}
actual++
}
return errs.Resolve()
}
// Open tests that the collection is opened.
func (t *CollectionTester[T]) Open() error {
if err := t.C.Open(); err != nil {
return fmt.Errorf("failed to open collection: %v", err)
}
return nil
}
// Put tests that the collection can store all documents.
func (t *CollectionTester[T]) Put() error {
errs := Errors{}
for key, data := range t.Data {
if err := t.C.Put(key, data); err != nil {
errs = append(errs, fmt.Errorf("failed to put document '%s': %v", key, err))
}
}
return errs.Resolve()
}
func (t *CollectionTester[T]) Close() error {
if err := t.C.Close(); err != nil {
return fmt.Errorf("failed to close collection: %v", err)
}
return nil
}