123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192 |
- 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
- }
|