storage_test.gno

7.36 Kb ยท 375 lines
  1package datastore
  2
  3import (
  4	"strings"
  5	"testing"
  6
  7	"gno.land/p/demo/uassert"
  8	"gno.land/p/demo/urequire"
  9)
 10
 11func TestStorageDefaults(t *testing.T) {
 12	name := "foo"
 13	storage := NewStorage(name)
 14
 15	uassert.Equal(t, name, storage.Name())
 16	uassert.NotEqual(t, nil, storage.Collection())
 17	uassert.Equal(t, 0, storage.Size())
 18
 19	s := storage.Schema()
 20	uassert.NotEqual(t, nil, s)
 21	uassert.Equal(t, strings.Title(name), s.Name())
 22}
 23
 24func TestStorageNewRecord(t *testing.T) {
 25	field := "status"
 26	defaultValue := "testing"
 27	s := NewSchema("Foo", WithDefaultField(field, defaultValue))
 28	storage := NewStorage("foo", WithSchema(s))
 29
 30	r := storage.NewRecord()
 31	urequire.NotEqual(t, nil, r, "new record is not nil")
 32	uassert.Equal(t, uint64(0), r.ID())
 33	uassert.Equal(t, storage.Schema().Name(), r.Type())
 34
 35	v, found := r.Get(field)
 36	urequire.True(t, found, "default value found")
 37
 38	got, ok := v.(string)
 39	urequire.True(t, ok, "default value type")
 40	uassert.Equal(t, defaultValue, got)
 41}
 42
 43func TestStorageQuery(t *testing.T) {
 44	index := NewIndex("tag", func(r Record) string {
 45		if v, found := r.Get("tag"); found {
 46			return v.(string)
 47		}
 48		return ""
 49	})
 50
 51	cases := []struct {
 52		name    string
 53		options []QueryOption
 54		results []uint64
 55		setup   func() *Storage
 56		errMsg  string
 57	}{
 58		{
 59			name:    "default query",
 60			results: []uint64{1, 2},
 61			setup: func() *Storage {
 62				s := NewStorage("foo")
 63				s.NewRecord().Save()
 64				s.NewRecord().Save()
 65				return &s
 66			},
 67		},
 68		{
 69			name:    "with size",
 70			results: []uint64{1},
 71			options: []QueryOption{WithSize(1)},
 72			setup: func() *Storage {
 73				s := NewStorage("foo")
 74				s.NewRecord().Save()
 75				s.NewRecord().Save()
 76				return &s
 77			},
 78		},
 79		{
 80			name:    "with offset",
 81			results: []uint64{2},
 82			options: []QueryOption{WithOffset(1)},
 83			setup: func() *Storage {
 84				s := NewStorage("foo")
 85				s.NewRecord().Save()
 86				s.NewRecord().Save()
 87				return &s
 88			},
 89		},
 90		{
 91			name:    "with offset overflow",
 92			options: []QueryOption{WithOffset(4)},
 93			setup: func() *Storage {
 94				s := NewStorage("foo")
 95				s.NewRecord().Save()
 96				return &s
 97			},
 98		},
 99		{
100			name:    "with size and offset",
101			results: []uint64{2, 3},
102			options: []QueryOption{WithSize(2), WithOffset(1)},
103			setup: func() *Storage {
104				s := NewStorage("foo")
105				s.NewRecord().Save()
106				s.NewRecord().Save()
107				s.NewRecord().Save()
108				s.NewRecord().Save()
109				return &s
110			},
111		},
112		{
113			name:    "custom index",
114			options: []QueryOption{UseIndex("tag", "A")},
115			results: []uint64{1, 3},
116			setup: func() *Storage {
117				s := NewStorage("foo", WithIndex(index))
118
119				r := s.NewRecord()
120				r.Set("tag", "A")
121				r.Save()
122
123				r = s.NewRecord()
124				r.Set("tag", "B")
125				r.Save()
126
127				r = s.NewRecord()
128				r.Set("tag", "A")
129				r.Save()
130
131				return &s
132			},
133		},
134		{
135			name:    "custom index with offset",
136			options: []QueryOption{UseIndex("tag", "B"), WithOffset(1)},
137			results: []uint64{3, 4},
138			setup: func() *Storage {
139				s := NewStorage("foo", WithIndex(index))
140
141				r := s.NewRecord()
142				r.Set("tag", "B")
143				r.Save()
144
145				r = s.NewRecord()
146				r.Set("tag", "A")
147				r.Save()
148
149				r = s.NewRecord()
150				r.Set("tag", "B")
151				r.Save()
152
153				r = s.NewRecord()
154				r.Set("tag", "B")
155				r.Save()
156
157				return &s
158			},
159		},
160		{
161			name:    "custom index with offset and size",
162			options: []QueryOption{UseIndex("tag", "B"), WithOffset(1), WithSize(1)},
163			results: []uint64{3},
164			setup: func() *Storage {
165				s := NewStorage("foo", WithIndex(index))
166
167				r := s.NewRecord()
168				r.Set("tag", "B")
169				r.Save()
170
171				r = s.NewRecord()
172				r.Set("tag", "A")
173				r.Save()
174
175				r = s.NewRecord()
176				r.Set("tag", "B")
177				r.Save()
178
179				r = s.NewRecord()
180				r.Set("tag", "B")
181				r.Save()
182
183				return &s
184			},
185		},
186		{
187			name:    "custom index not found",
188			options: []QueryOption{UseIndex("foo", "B")},
189			setup: func() *Storage {
190				s := NewStorage("foo")
191				return &s
192			},
193			errMsg: "storage index for query not found: foo",
194		},
195	}
196
197	for _, tc := range cases {
198		t.Run(tc.name, func(t *testing.T) {
199			// Arrange
200			storage := tc.setup()
201
202			// Act
203			rs, err := storage.Query(tc.options...)
204
205			// Assert
206			if tc.errMsg != "" {
207				uassert.ErrorContains(t, err, tc.errMsg, "expect error")
208				return
209			}
210
211			urequire.NoError(t, err, "expect no error")
212			urequire.NotEqual(t, nil, rs, "new record is not nil")
213			urequire.Equal(t, len(tc.results), rs.Size(), "expect query results count to match")
214
215			var i int
216			rs.Iterate(func(r Record) bool {
217				urequire.Equal(t, tc.results[i], r.ID(), "expect result IDs to match")
218				i++
219				return false
220			})
221		})
222	}
223}
224
225func TestStorageGet(t *testing.T) {
226	index := NewIndex("name", func(r Record) string {
227		if v, found := r.Get("name"); found {
228			return v.(string)
229		}
230		return ""
231	})
232
233	cases := []struct {
234		name     string
235		key      string
236		recordID uint64
237		setup    func(*Storage)
238	}{
239		{
240			name:     "single record",
241			key:      "foobar",
242			recordID: 1,
243			setup: func(s *Storage) {
244				r := s.NewRecord()
245				r.Set("name", "foobar")
246				r.Save()
247			},
248		},
249		{
250			name:     "two records",
251			key:      "foobar",
252			recordID: 1,
253			setup: func(s *Storage) {
254				r := s.NewRecord()
255				r.Set("name", "foobar")
256				r.Save()
257
258				r = s.NewRecord()
259				r.Set("name", "foobar")
260				r.Save()
261
262				r = s.NewRecord()
263				r.Set("name", "extra")
264				r.Save()
265			},
266		},
267		{
268			name: "record not found",
269			key:  "unknown",
270			setup: func(s *Storage) {
271				r := s.NewRecord()
272				r.Set("name", "foobar")
273				r.Save()
274			},
275		},
276		{
277			name: "empty storage",
278			key:  "foobar",
279		},
280	}
281
282	for _, tc := range cases {
283		t.Run(tc.name, func(t *testing.T) {
284			storage := NewStorage("foo", WithIndex(index))
285			if tc.setup != nil {
286				tc.setup(&storage)
287			}
288
289			r, found := storage.Get(index.Name(), tc.key)
290
291			if tc.recordID == 0 {
292				uassert.Equal(t, nil, r, "expect no record")
293				uassert.False(t, found, "expect record not found")
294				return
295			}
296
297			uassert.True(t, found, "expect record found")
298			urequire.NotEqual(t, nil, r, "expect record to be found")
299			uassert.Equal(t, tc.recordID, r.ID(), "expect ID to match")
300		})
301	}
302}
303
304func TestStorageGetByID(t *testing.T) {
305	cases := []struct {
306		name     string
307		recordID uint64
308		found    bool
309		setup    func(*Storage)
310	}{
311		{
312			name:     "single record",
313			recordID: 1,
314			found:    true,
315			setup: func(s *Storage) {
316				s.NewRecord().Save()
317			},
318		},
319		{
320			name:     "multiple records",
321			recordID: 2,
322			found:    true,
323			setup: func(s *Storage) {
324				s.NewRecord().Save()
325				s.NewRecord().Save()
326				s.NewRecord().Save()
327			},
328		},
329		{
330			name:     "record not found",
331			recordID: 3,
332			setup: func(s *Storage) {
333				s.NewRecord().Save()
334				s.NewRecord().Save()
335			},
336		},
337		{
338			name:     "empty storage",
339			recordID: 1,
340		},
341	}
342
343	for _, tc := range cases {
344		t.Run(tc.name, func(t *testing.T) {
345			storage := NewStorage("foo")
346			if tc.setup != nil {
347				tc.setup(&storage)
348			}
349
350			r, found := storage.GetByID(tc.recordID)
351
352			if !tc.found {
353				uassert.Equal(t, nil, r, "expect no record")
354				uassert.False(t, found, "expect record not found")
355				return
356			}
357
358			uassert.True(t, found, "expect record found")
359			urequire.NotEqual(t, nil, r, "expect record to be found")
360			uassert.Equal(t, tc.recordID, r.ID(), "expect ID to match")
361		})
362	}
363}
364
365func TestStorageDelete(t *testing.T) {
366	storage := NewStorage("foo")
367	r := storage.NewRecord()
368	r.Save()
369
370	deleted := storage.Delete(r.ID())
371	uassert.True(t, deleted)
372
373	deleted = storage.Delete(r.ID())
374	uassert.False(t, deleted)
375}