Files
SugarDB/sugardb/api_set_test.go
Kelvin Mwinuka 63a4652d9f Refactor tests (#171)
- Refactored tests to improve execution time - @kelvinmwinuka
2025-01-27 01:42:41 +08:00

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