mirror of
https://github.com/EchoVault/SugarDB.git
synced 2025-09-27 04:16:06 +08:00
1220 lines
38 KiB
Go
1220 lines
38 KiB
Go
// Copyright 2024 Kelvin Clement Mwinuka
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package sugardb
|
|
|
|
import (
|
|
"context"
|
|
"github.com/echovault/sugardb/internal/modules/set"
|
|
"reflect"
|
|
"slices"
|
|
"testing"
|
|
)
|
|
|
|
func TestSugarDB_Set(t *testing.T) {
|
|
server := createSugarDB()
|
|
|
|
t.Cleanup(func() {
|
|
server.ShutDown()
|
|
})
|
|
|
|
t.Run("TestSugarDB_SADD", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
presetValue interface{}
|
|
key string
|
|
members []string
|
|
want int
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "1. Create new set on a non-existent key, return count of added elements",
|
|
presetValue: nil,
|
|
key: "sadd_key1",
|
|
members: []string{"one", "two", "three", "four"},
|
|
want: 4,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "2. Add members to an exiting set, skip members that already exist in the set, return added count",
|
|
presetValue: set.NewSet([]string{"one", "two", "three", "four"}),
|
|
key: "sadd_key2",
|
|
members: []string{"three", "four", "five", "six", "seven"},
|
|
want: 3,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "2. Throw error when trying to add to a key that does not hold a set",
|
|
presetValue: "Default value",
|
|
key: "sadd_key3",
|
|
members: []string{"member"},
|
|
want: 0,
|
|
wantErr: true,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if tt.presetValue != nil {
|
|
err := presetValue(server, context.Background(), tt.key, tt.presetValue)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
}
|
|
got, err := server.SAdd(tt.key, tt.members...)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("SADD() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if got != tt.want {
|
|
t.Errorf("SADD() got = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("TestSugarDB_SCARD", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
presetValue interface{}
|
|
key string
|
|
want int
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "1. Get cardinality of valid set",
|
|
presetValue: set.NewSet([]string{"one", "two", "three", "four"}),
|
|
key: "scard_key1",
|
|
want: 4,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "2. Return 0 when trying to get cardinality on non-existent key",
|
|
presetValue: nil,
|
|
key: "scard_key2",
|
|
want: 0,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "3. Throw error when trying to get cardinality of a value that is not a set",
|
|
presetValue: "Default value",
|
|
key: "scard_key3",
|
|
want: 0,
|
|
wantErr: true,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if tt.presetValue != nil {
|
|
err := presetValue(server, context.Background(), tt.key, tt.presetValue)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
}
|
|
got, err := server.SCard(tt.key)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("SCARD() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if got != tt.want {
|
|
t.Errorf("SCARD() got = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("TestSugarDB_SDIFF", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
presetValues map[string]interface{}
|
|
keys []string
|
|
want []string
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "1. Get the difference between 2 sets",
|
|
presetValues: map[string]interface{}{
|
|
"sdiff_key1": set.NewSet([]string{"one", "two", "three", "four", "five"}),
|
|
"sdiff_key2": set.NewSet([]string{"three", "four", "five", "six", "seven", "eight"}),
|
|
},
|
|
keys: []string{"sdiff_key1", "sdiff_key2"},
|
|
want: []string{"one", "two"},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "2. Get the difference between 3 sets",
|
|
presetValues: map[string]interface{}{
|
|
"sdiff_key3": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
|
|
"sdiff_key4": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven"}),
|
|
"sdiff_key5": set.NewSet([]string{"seven", "eight", "nine", "ten", "twelve"}),
|
|
},
|
|
keys: []string{"sdiff_key3", "sdiff_key4", "sdiff_key5"},
|
|
want: []string{"three", "four", "five", "six"},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "3. Return base set element if base set is the only valid set",
|
|
presetValues: map[string]interface{}{
|
|
"sdiff_key6": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
|
|
"sdiff_key7": "Default value",
|
|
"sdiff_key8": 123456789,
|
|
},
|
|
keys: []string{"sdiff_key6", "sdiff_key7", "sdiff_key8"},
|
|
want: []string{"one", "two", "three", "four", "five", "six", "seven", "eight"},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "4. Throw error when base set is not a set",
|
|
presetValues: map[string]interface{}{
|
|
"sdiff_key9": "Default value",
|
|
"sdiff_key10": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven"}),
|
|
"sdiff_key11": set.NewSet([]string{"seven", "eight", "nine", "ten", "twelve"}),
|
|
},
|
|
keys: []string{"sdiff_key9", "sdiff_key10", "sdiff_key11"},
|
|
want: nil,
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "5. Throw error when base set is non-existent",
|
|
presetValues: map[string]interface{}{
|
|
"sdiff_key12": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven"}),
|
|
"sdiff_key13": set.NewSet([]string{"seven", "eight", "nine", "ten", "twelve"}),
|
|
},
|
|
keys: []string{"sdiff_non-existent", "sdiff_key7", "sdiff_key8"},
|
|
want: nil,
|
|
wantErr: true,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if tt.presetValues != nil {
|
|
for k, v := range tt.presetValues {
|
|
err := presetValue(server, context.Background(), k, v)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
got, err := server.SDiff(tt.keys...)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("SDIFF() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if len(got) != len(tt.want) {
|
|
t.Errorf("SDIFF() got = %v, want %v", got, tt.want)
|
|
}
|
|
for _, g := range got {
|
|
if !slices.Contains(tt.want, g) {
|
|
t.Errorf("SDIFF() got = %v, want %v", got, tt.want)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("TestSugarDB_SDIFFSTORE", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
presetValues map[string]interface{}
|
|
destination string
|
|
keys []string
|
|
want int
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "1. Get the difference between 2 sets",
|
|
presetValues: map[string]interface{}{
|
|
"sdiffstore_key1": set.NewSet([]string{"one", "two", "three", "four", "five"}),
|
|
"sdiffstore_key2": set.NewSet([]string{"three", "four", "five", "six", "seven", "eight"}),
|
|
},
|
|
destination: "sdiffstore_destination1",
|
|
keys: []string{"sdiffstore_key1", "sdiffstore_key2"},
|
|
want: 2,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "2. Get the difference between 3 sets",
|
|
presetValues: map[string]interface{}{
|
|
"sdiffstore_key3": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
|
|
"sdiffstore_key4": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven"}),
|
|
"sdiffstore_key5": set.NewSet([]string{"seven", "eight", "nine", "ten", "twelve"}),
|
|
},
|
|
destination: "sdiffstore_destination2",
|
|
keys: []string{"sdiffstore_key3", "sdiffstore_key4", "sdiffstore_key5"},
|
|
want: 4,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "3. Return base set element if base set is the only valid set",
|
|
presetValues: map[string]interface{}{
|
|
"sdiffstore_key6": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
|
|
"sdiffstore_key7": "Default value",
|
|
"sdiffstore_key8": 123456789,
|
|
},
|
|
destination: "sdiffstore_destination3",
|
|
keys: []string{"sdiffstore_key6", "sdiffstore_key7", "sdiffstore_key8"},
|
|
want: 8,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "4. Throw error when base set is not a set",
|
|
presetValues: map[string]interface{}{
|
|
"sdiffstore_key9": "Default value",
|
|
"sdiffstore_key10": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven"}),
|
|
"sdiffstore_key11": set.NewSet([]string{"seven", "eight", "nine", "ten", "twelve"}),
|
|
},
|
|
destination: "sdiffstore_destination4",
|
|
keys: []string{"sdiffstore_key9", "sdiffstore_key10", "sdiffstore_key11"},
|
|
want: 0,
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "5. Throw error when base set is non-existent",
|
|
presetValues: map[string]interface{}{
|
|
"sdiffstore_key12": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven"}),
|
|
"sdiffstore_key13": set.NewSet([]string{"seven", "eight", "nine", "ten", "twelve"}),
|
|
},
|
|
destination: "sdiffstore_destination5",
|
|
keys: []string{"sdiffstore_non-existent", "sdiffstore_key7", "sdiffstore_key8"},
|
|
want: 0,
|
|
wantErr: true,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if tt.presetValues != nil {
|
|
for k, v := range tt.presetValues {
|
|
err := presetValue(server, context.Background(), k, v)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
got, err := server.SDiffStore(tt.destination, tt.keys...)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("SDIFFSTORE() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if got != tt.want {
|
|
t.Errorf("SDIFFSTORE() got = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("TestSugarDB_SINTER", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
presetValues map[string]interface{}
|
|
keys []string
|
|
want []string
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "1. Get the intersection between 2 sets",
|
|
presetValues: map[string]interface{}{
|
|
"sinter_key1": set.NewSet([]string{"one", "two", "three", "four", "five"}),
|
|
"sinter_key2": set.NewSet([]string{"three", "four", "five", "six", "seven", "eight"}),
|
|
},
|
|
keys: []string{"sinter_key1", "sinter_key2"},
|
|
want: []string{"three", "four", "five"},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "2. Get the intersection between 3 sets",
|
|
presetValues: map[string]interface{}{
|
|
"sinter_key3": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
|
|
"sinter_key4": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven", "eight"}),
|
|
"sinter_key5": set.NewSet([]string{"one", "eight", "nine", "ten", "twelve"}),
|
|
},
|
|
keys: []string{"sinter_key3", "sinter_key4", "sinter_key5"},
|
|
want: []string{"one", "eight"},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "3. Throw an error if any of the provided keys are not sets",
|
|
presetValues: map[string]interface{}{
|
|
"sinter_key6": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
|
|
"sinter_key7": "Default value",
|
|
"sinter_key8": set.NewSet([]string{"one"}),
|
|
},
|
|
keys: []string{"sinter_key6", "sinter_key7", "sinter_key8"},
|
|
want: nil,
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "4. Throw error when base set is not a set",
|
|
presetValues: map[string]interface{}{
|
|
"sinter_key9": "Default value",
|
|
"sinter_key10": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven"}),
|
|
"sinter_key11": set.NewSet([]string{"seven", "eight", "nine", "ten", "twelve"}),
|
|
},
|
|
keys: []string{"sinter_key9", "sinter_key10", "sinter_key11"},
|
|
want: nil,
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "5. If any of the keys does not exist, return an empty array",
|
|
presetValues: map[string]interface{}{
|
|
"sinter_key12": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven"}),
|
|
"sinter_key13": set.NewSet([]string{"seven", "eight", "nine", "ten", "twelve"}),
|
|
},
|
|
keys: []string{"sinter_non-existent", "sinter_key12", "sinter_key13"},
|
|
want: []string{},
|
|
wantErr: false,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if tt.presetValues != nil {
|
|
for k, v := range tt.presetValues {
|
|
err := presetValue(server, context.Background(), k, v)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
got, err := server.SInter(tt.keys...)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("SINTER() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if len(got) != len(tt.want) {
|
|
t.Errorf("SINTER() got = %v, want %v", got, tt.want)
|
|
}
|
|
for _, g := range got {
|
|
if !slices.Contains(tt.want, g) {
|
|
t.Errorf("SINTER() got = %v, want %v", got, tt.want)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("TestSugarDB_SINTERCARD", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
presetValues map[string]interface{}
|
|
keys []string
|
|
limit uint
|
|
want int
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "1. Get the full intersect cardinality between 2 sets",
|
|
presetValues: map[string]interface{}{
|
|
"sintercard_key1": set.NewSet([]string{"one", "two", "three", "four", "five"}),
|
|
"sintercard_key2": set.NewSet([]string{"three", "four", "five", "six", "seven", "eight"}),
|
|
},
|
|
keys: []string{"sintercard_key1", "sintercard_key2"},
|
|
limit: 0,
|
|
want: 3,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "2. Get an intersect cardinality between 2 sets with a limit",
|
|
presetValues: map[string]interface{}{
|
|
"sintercard_key3": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"}),
|
|
"sintercard_key4": set.NewSet([]string{"three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve"}),
|
|
},
|
|
keys: []string{"sintercard_key3", "sintercard_key4"},
|
|
limit: 3,
|
|
want: 3,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "3. Get the full intersect cardinality between 3 sets",
|
|
presetValues: map[string]interface{}{
|
|
"sintercard_key5": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
|
|
"sintercard_key6": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven", "eight"}),
|
|
"sintercard_key7": set.NewSet([]string{"one", "seven", "eight", "nine", "ten", "twelve"}),
|
|
},
|
|
keys: []string{"sintercard_key5", "sintercard_key6", "sintercard_key7"},
|
|
limit: 0,
|
|
want: 2,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "4. Get the intersection of 3 sets with a limit",
|
|
presetValues: map[string]interface{}{
|
|
"sintercard_key8": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
|
|
"sintercard_key9": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven", "eight"}),
|
|
"sintercard_key10": set.NewSet([]string{"one", "two", "seven", "eight", "nine", "ten", "twelve"}),
|
|
},
|
|
keys: []string{"sintercard_key8", "sintercard_key9", "sintercard_key10"},
|
|
limit: 2,
|
|
want: 2,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "5. Return error if any of the keys is non-existent",
|
|
presetValues: map[string]interface{}{
|
|
"sintercard_key11": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
|
|
"sintercard_key13": set.NewSet([]string{"one"}),
|
|
},
|
|
keys: []string{"sintercard_key11", "sintercard_key12", "sintercard_key13"},
|
|
limit: 0,
|
|
want: 0,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "6. Throw error when one of the keys is not a valid set",
|
|
presetValues: map[string]interface{}{
|
|
"sintercard_key14": "Default value",
|
|
"sintercard_key15": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven"}),
|
|
"sintercard_key16": set.NewSet([]string{"seven", "eight", "nine", "ten", "twelve"}),
|
|
},
|
|
keys: []string{"sintercard_key14", "sintercard_key15", "sintercard_key16"},
|
|
want: 0,
|
|
wantErr: true,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if tt.presetValues != nil {
|
|
for k, v := range tt.presetValues {
|
|
err := presetValue(server, context.Background(), k, v)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
got, err := server.SInterCard(tt.keys, tt.limit)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("SINTERCARD() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if got != tt.want {
|
|
t.Errorf("SINTERCARD() got = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("TestSugarDB_SINTERSTORE", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
presetValues map[string]interface{}
|
|
destination string
|
|
keys []string
|
|
want int
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "1. Get the intersection between 2 sets and store it at the destination",
|
|
presetValues: map[string]interface{}{
|
|
"sinterstore_key1": set.NewSet([]string{"one", "two", "three", "four", "five"}),
|
|
"sinterstore_key2": set.NewSet([]string{"three", "four", "five", "six", "seven", "eight"}),
|
|
},
|
|
destination: "sinterstore_destination1",
|
|
keys: []string{"sinterstore_key1", "sinterstore_key2"},
|
|
want: 3,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "2. Get the intersection between 3 sets and store it at the destination key",
|
|
presetValues: map[string]interface{}{
|
|
"sinterstore_key3": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
|
|
"sinterstore_key4": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven", "eight"}),
|
|
"sinterstore_key5": set.NewSet([]string{"one", "seven", "eight", "nine", "ten", "twelve"}),
|
|
},
|
|
destination: "sinterstore_destination2",
|
|
keys: []string{"sinterstore_key3", "sinterstore_key4", "sinterstore_key5"},
|
|
want: 2,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "3. Throw error when any of the keys is not a set",
|
|
presetValues: map[string]interface{}{
|
|
"sinterstore_key6": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
|
|
"sinterstore_key7": "Default value",
|
|
"sinterstore_key8": set.NewSet([]string{"one"}),
|
|
},
|
|
destination: "sinterstore_destination3",
|
|
keys: []string{"sinterstore_key6", "sinterstore_key7", "sinterstore_key8"},
|
|
want: 0,
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "4. Throw error when base set is not a set",
|
|
presetValues: map[string]interface{}{
|
|
"sinterstore_key9": "Default value",
|
|
"sinterstore_key10": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven"}),
|
|
"sinterstore_key11": set.NewSet([]string{"seven", "eight", "nine", "ten", "twelve"}),
|
|
},
|
|
destination: "sinterstore_destination4",
|
|
keys: []string{"sinterstore_key9", "sinterstore_key10", "sinterstore_key11"},
|
|
want: 0,
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "5. Return an empty intersection if one of the keys does not exist",
|
|
presetValues: map[string]interface{}{
|
|
"sinterstore_key12": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven"}),
|
|
"sinterstore_key13": set.NewSet([]string{"seven", "eight", "nine", "ten", "twelve"}),
|
|
},
|
|
destination: "sinterstore_destination5",
|
|
keys: []string{"sinterstore_non-existent", "sinterstore_key12", "sinterstore_key13"},
|
|
want: 0,
|
|
wantErr: false,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if tt.presetValues != nil {
|
|
for k, v := range tt.presetValues {
|
|
err := presetValue(server, context.Background(), k, v)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
got, err := server.SInterStore(tt.destination, tt.keys...)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("SINTERSTORE() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if got != tt.want {
|
|
t.Errorf("SINTERSTORE() got = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("TestSugarDB_SISMEMBER", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
presetValue interface{}
|
|
key string
|
|
member string
|
|
want bool
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "1. Return true when element is a member of the set",
|
|
presetValue: set.NewSet([]string{"one", "two", "three", "four"}),
|
|
key: "sismember_key1",
|
|
member: "three",
|
|
want: true,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "2. Return false when element is not a member of the set",
|
|
presetValue: set.NewSet([]string{"one", "two", "three", "four"}),
|
|
key: "sismember_key2",
|
|
member: "five",
|
|
want: false,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "3. Throw error when trying to assert membership when the key does not hold a valid set",
|
|
presetValue: "Default value",
|
|
key: "sismember_key3",
|
|
member: "one",
|
|
want: false,
|
|
wantErr: true,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if tt.presetValue != nil {
|
|
err := presetValue(server, context.Background(), tt.key, tt.presetValue)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
}
|
|
got, err := server.SisMember(tt.key, tt.member)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("SISMEMBER() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if got != tt.want {
|
|
t.Errorf("SISMEMBER() got = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("TestSugarDB_SMEMBERS", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
presetValue interface{}
|
|
key string
|
|
want []string
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "1. Return all the members of the set",
|
|
key: "smembers_key1",
|
|
presetValue: set.NewSet([]string{"one", "two", "three", "four", "five"}),
|
|
want: []string{"one", "two", "three", "four", "five"},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "2. If the key does not exist, return an empty array",
|
|
key: "smembers_key2",
|
|
presetValue: nil,
|
|
want: []string{},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "3. Throw error when the provided key is not a set",
|
|
key: "smembers_key3",
|
|
presetValue: "Default value",
|
|
want: nil,
|
|
wantErr: true,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if tt.presetValue != nil {
|
|
err := presetValue(server, context.Background(), tt.key, tt.presetValue)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
}
|
|
got, err := server.SMembers(tt.key)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("SMEMBERS() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if len(got) != len(tt.want) {
|
|
t.Errorf("SMEMBERS() got = %v, want %v", got, tt.want)
|
|
}
|
|
for _, g := range got {
|
|
if !slices.Contains(tt.want, g) {
|
|
t.Errorf("SMEMBERS() got = %v, want %v", got, tt.want)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("TestSugarDB_SMISMEMBER", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
presetValue interface{}
|
|
key string
|
|
members []string
|
|
want []bool
|
|
wantErr bool
|
|
}{
|
|
{
|
|
// Return set membership status for multiple elements (true for present and false for absent).
|
|
// The placement of the membership status flag should be consistent with the order the elements
|
|
// are in within the original command
|
|
name: "1. Return set membership status for multiple elements",
|
|
presetValue: set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven"}),
|
|
key: "smismember_key1",
|
|
members: []string{"three", "four", "five", "six", "eight", "nine", "seven"},
|
|
want: []bool{true, true, true, true, false, false, true},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "2. If the set key does not exist, return an array of zeroes as long as the list of members",
|
|
presetValue: nil,
|
|
key: "smismember_key2",
|
|
members: []string{"one", "two", "three", "four"},
|
|
want: []bool{false, false, false, false},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "3. Throw error when trying to assert membership when the key does not hold a valid set",
|
|
presetValue: "Default value",
|
|
key: "smismember_key3",
|
|
members: []string{"one"},
|
|
want: nil,
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "4. Throw error for empty member slice",
|
|
presetValue: nil,
|
|
key: "smismember_key4",
|
|
members: []string{},
|
|
want: nil,
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "5. Throw error for nil member slice",
|
|
presetValue: nil,
|
|
key: "smismember_key4",
|
|
members: nil,
|
|
want: nil,
|
|
wantErr: true,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if tt.presetValue != nil {
|
|
err := presetValue(server, context.Background(), tt.key, tt.presetValue)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
}
|
|
got, err := server.SMisMember(tt.key, tt.members...)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("SMISMEMBER() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("SMISMEMBER() got = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("TestSugarDB_SMOVE", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
presetValues map[string]interface{}
|
|
source string
|
|
destination string
|
|
member string
|
|
want bool
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "1. Return true after a successful move of a member from source set to destination set",
|
|
presetValues: map[string]interface{}{
|
|
"smove_source1": set.NewSet([]string{"one", "two", "three", "four"}),
|
|
"smove_destination1": set.NewSet([]string{"five", "six", "seven", "eight"}),
|
|
},
|
|
source: "smove_source1",
|
|
destination: "smove_destination1",
|
|
member: "four",
|
|
want: true,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "2. Return false when trying to move a member from source set to destination set when it doesn't exist in source",
|
|
presetValues: map[string]interface{}{
|
|
"smove_source2": set.NewSet([]string{"one", "two", "three", "four", "five"}),
|
|
"smove_destination2": set.NewSet([]string{"five", "six", "seven", "eight"}),
|
|
},
|
|
source: "smove_source2",
|
|
destination: "smove_destination2",
|
|
member: "six",
|
|
want: false,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "3. Return error when the source key is not a set",
|
|
presetValues: map[string]interface{}{
|
|
"smove_source3": "Default value",
|
|
"smove_destination3": set.NewSet([]string{"five", "six", "seven", "eight"}),
|
|
},
|
|
source: "smove_source3",
|
|
destination: "smove_destination3",
|
|
member: "five",
|
|
want: false,
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "4. Return error when the destination key is not a set",
|
|
presetValues: map[string]interface{}{
|
|
"smove_source4": set.NewSet([]string{"one", "two", "three", "four", "five"}),
|
|
"smove_destination4": "Default value",
|
|
},
|
|
source: "smove_source4",
|
|
destination: "smove_destination4",
|
|
member: "five",
|
|
want: false,
|
|
wantErr: true,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if tt.presetValues != nil {
|
|
for k, v := range tt.presetValues {
|
|
err := presetValue(server, context.Background(), k, v)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
got, err := server.SMove(tt.source, tt.destination, tt.member)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("SMOVE() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if got != tt.want {
|
|
t.Errorf("SMOVE() got = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("TestSugarDB_SPOP", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
presetValue interface{}
|
|
key string
|
|
count uint
|
|
want []string
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "1. Return multiple popped elements and modify the set",
|
|
key: "spop_key1",
|
|
presetValue: set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
|
|
count: 3,
|
|
want: []string{"one", "two", "three", "four", "five", "six", "seven", "eight"},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "2. Return error when the source key is not a set",
|
|
key: "spop_key2",
|
|
presetValue: "Default value",
|
|
count: 1,
|
|
want: nil,
|
|
wantErr: true,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if tt.presetValue != nil {
|
|
err := presetValue(server, context.Background(), tt.key, tt.presetValue)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
}
|
|
got, err := server.SPop(tt.key, tt.count)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("SPOP() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
for _, g := range got {
|
|
if !slices.Contains(tt.want, g) {
|
|
t.Errorf("SPOP() got = %v, want %v", got, tt.want)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("TestSugarDB_SRANDMEMBER", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
presetValue interface{}
|
|
key string
|
|
count int
|
|
wantCount int
|
|
wantErr bool
|
|
}{
|
|
{
|
|
// Return multiple random elements without removing them
|
|
// Count is positive, do not allow repeated elements
|
|
name: "1. Return multiple random elements without removing them",
|
|
key: "srandmember_key1",
|
|
presetValue: set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
|
|
count: 3,
|
|
wantCount: 3,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
// Return multiple random elements without removing them
|
|
// Count is negative, so allow repeated numbers
|
|
name: "2. Return multiple random elements without removing them",
|
|
key: "srandmember_key2",
|
|
presetValue: set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
|
|
count: -5,
|
|
wantCount: 5,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "3. Return error when the source key is not a set",
|
|
key: "srandmember_key3",
|
|
presetValue: "Default value",
|
|
count: 1,
|
|
wantCount: 0,
|
|
wantErr: true,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if tt.presetValue != nil {
|
|
err := presetValue(server, context.Background(), tt.key, tt.presetValue)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
}
|
|
got, err := server.SRandMember(tt.key, tt.count)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("SRANDMEMBER() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if len(got) != tt.wantCount {
|
|
t.Errorf("SRANDMEMBER() got = %v, want %v", len(got), tt.wantCount)
|
|
}
|
|
if tt.count > 0 {
|
|
s := set.NewSet(got)
|
|
if s.Cardinality() != len(got) {
|
|
t.Errorf("SRANDMEMBER - UNIQUE () got = %v, want %v", len(got), s.Cardinality())
|
|
}
|
|
}
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("TestSugarDB_SREM", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
presetValue interface{}
|
|
key string
|
|
members []string
|
|
want int
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "1. Remove multiple elements and return the number of elements removed",
|
|
key: "srem_key1",
|
|
presetValue: set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
|
|
members: []string{"one", "two", "three", "nine"},
|
|
want: 3,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "2. If key does not exist, return 0",
|
|
key: "srem_key2",
|
|
presetValue: nil,
|
|
members: []string{"one", "two", "three", "nine"},
|
|
want: 0,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "3. Return error when the source key is not a set",
|
|
key: "srem_key3",
|
|
presetValue: "Default value",
|
|
members: []string{"one"},
|
|
want: 0,
|
|
wantErr: true,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if tt.presetValue != nil {
|
|
err := presetValue(server, context.Background(), tt.key, tt.presetValue)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
}
|
|
got, err := server.SRem(tt.key, tt.members...)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("SREM() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if got != tt.want {
|
|
t.Errorf("SREM() got = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("TestSugarDB_SUNION", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
presetValues map[string]interface{}
|
|
keys []string
|
|
want []string
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "1. Get the union between 2 sets",
|
|
presetValues: map[string]interface{}{
|
|
"sunion_key1": set.NewSet([]string{"one", "two", "three", "four", "five"}),
|
|
"sunion_key2": set.NewSet([]string{"three", "four", "five", "six", "seven", "eight"}),
|
|
},
|
|
keys: []string{"sunion_key1", "sunion_key2"},
|
|
want: []string{"one", "two", "three", "four", "five", "six", "seven", "eight"},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "2. Get the union between 3 sets",
|
|
presetValues: map[string]interface{}{
|
|
"sunion_key3": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
|
|
"sunion_key4": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven", "eight"}),
|
|
"sunion_key5": set.NewSet([]string{"one", "eight", "nine", "ten", "twelve"}),
|
|
},
|
|
keys: []string{"sunion_key3", "sunion_key4", "sunion_key5"},
|
|
want: []string{
|
|
"one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
|
|
"ten", "eleven", "twelve", "thirty-six",
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "3. Throw an error if any of the provided keys are not sets",
|
|
presetValues: map[string]interface{}{
|
|
"sunion_key6": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
|
|
"sunion_key7": "Default value",
|
|
"sunion_key8": set.NewSet([]string{"one"}),
|
|
},
|
|
keys: []string{"sunion_key6", "sunion_key7", "sunion_key8"},
|
|
want: nil,
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "4. Throw error any of the keys does not hold a set",
|
|
presetValues: map[string]interface{}{
|
|
"sunion_key9": "Default value",
|
|
"sunion_key10": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven"}),
|
|
"sunion_key11": set.NewSet([]string{"seven", "eight", "nine", "ten", "twelve"}),
|
|
},
|
|
keys: []string{"sunion_key9", "sunion_key10", "sunion_key11"},
|
|
want: nil,
|
|
wantErr: true,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if tt.presetValues != nil {
|
|
for k, v := range tt.presetValues {
|
|
err := presetValue(server, context.Background(), k, v)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
got, err := server.SUnion(tt.keys...)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("SUNION() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if len(got) != len(tt.want) {
|
|
t.Errorf("SUNION() got = %v, want %v", got, tt.want)
|
|
}
|
|
for _, g := range got {
|
|
if !slices.Contains(tt.want, g) {
|
|
t.Errorf("SUNION() got = %v, want %v", got, tt.want)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("TestSugarDB_SUNIONSTORE", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
presetValues map[string]interface{}
|
|
destination string
|
|
keys []string
|
|
want int
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "1. Get the intersection between 2 sets and store it at the destination",
|
|
presetValues: map[string]interface{}{
|
|
"sunionstore_key1": set.NewSet([]string{"one", "two", "three", "four", "five"}),
|
|
"sunionstore_key2": set.NewSet([]string{"three", "four", "five", "six", "seven", "eight"}),
|
|
},
|
|
destination: "sunionstore_destination1",
|
|
keys: []string{"sunionstore_key1", "sunionstore_key2"},
|
|
want: 8,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "2. Get the intersection between 3 sets and store it at the destination key",
|
|
presetValues: map[string]interface{}{
|
|
"sunionstore_key3": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
|
|
"sunionstore_key4": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven", "eight"}),
|
|
"sunionstore_key5": set.NewSet([]string{"one", "seven", "eight", "nine", "ten", "twelve"}),
|
|
},
|
|
destination: "sunionstore_destination2",
|
|
keys: []string{"sunionstore_key3", "sunionstore_key4", "sunionstore_key5"},
|
|
want: 13,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "3. Throw error when any of the keys is not a set",
|
|
presetValues: map[string]interface{}{
|
|
"sunionstore_key6": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
|
|
"sunionstore_key7": "Default value",
|
|
"sunionstore_key8": set.NewSet([]string{"one"}),
|
|
},
|
|
destination: "sunionstore_destination3",
|
|
keys: []string{"sunionstore_key6", "sunionstore_key7", "sunionstore_key8"},
|
|
want: 0,
|
|
wantErr: true,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if tt.presetValues != nil {
|
|
for k, v := range tt.presetValues {
|
|
err := presetValue(server, context.Background(), k, v)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
got, err := server.SUnionStore(tt.destination, tt.keys...)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("SUNIONSTORE() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if got != tt.want {
|
|
t.Errorf("SUNIONSTORE() got = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
}
|