Files
SugarDB/echovault/api_set_test.go
Kelvin Clement Mwinuka 0108444d69 Replaced fmt.Println statements with log.Println.
Return "empty command" error from handleCommand method if an empty command is passed to the server.
Wait until connection is no longer nil in acl package tests.
2024-05-27 11:45:48 +08:00

1212 lines
35 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 echovault
import (
"context"
"github.com/echovault/echovault/internal/modules/set"
"reflect"
"slices"
"testing"
)
func TestEchoVault_SADD(t *testing.T) {
server := createEchoVault()
tests := []struct {
name string
presetValue interface{}
key string
members []string
want int
wantErr bool
}{
{
name: "Create new set on a non-existent key, return count of added elements",
presetValue: nil,
key: "key1",
members: []string{"one", "two", "three", "four"},
want: 4,
wantErr: false,
},
{
name: "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: "key2",
members: []string{"three", "four", "five", "six", "seven"},
want: 3,
wantErr: false,
},
{
name: "Throw error when trying to add to a key that does not hold a set",
presetValue: "Default value",
key: "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)
}
})
}
}
func TestEchoVault_SCARD(t *testing.T) {
server := createEchoVault()
tests := []struct {
name string
presetValue interface{}
key string
want int
wantErr bool
}{
{
name: "Get cardinality of valid set",
presetValue: set.NewSet([]string{"one", "two", "three", "four"}),
key: "key1",
want: 4,
wantErr: false,
},
{
name: "Return 0 when trying to get cardinality on non-existent key",
presetValue: nil,
key: "key2",
want: 0,
wantErr: false,
},
{
name: "Throw error when trying to get cardinality of a value that is not a set",
presetValue: "Default value",
key: "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)
}
})
}
}
func TestEchoVault_SDIFF(t *testing.T) {
server := createEchoVault()
tests := []struct {
name string
presetValues map[string]interface{}
keys []string
want []string
wantErr bool
}{
{
name: "Get the difference between 2 sets",
presetValues: map[string]interface{}{
"key1": set.NewSet([]string{"one", "two", "three", "four", "five"}),
"key2": set.NewSet([]string{"three", "four", "five", "six", "seven", "eight"}),
},
keys: []string{"key1", "key2"},
want: []string{"one", "two"},
wantErr: false,
},
{
name: "Get the difference between 3 sets",
presetValues: map[string]interface{}{
"key3": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
"key4": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven"}),
"key5": set.NewSet([]string{"seven", "eight", "nine", "ten", "twelve"}),
},
keys: []string{"key3", "key4", "key5"},
want: []string{"three", "four", "five", "six"},
wantErr: false,
},
{
name: "Return base set element if base set is the only valid set",
presetValues: map[string]interface{}{
"key6": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
"key7": "Default value",
"key8": 123456789,
},
keys: []string{"key6", "key7", "key8"},
want: []string{"one", "two", "three", "four", "five", "six", "seven", "eight"},
wantErr: false,
},
{
name: "Throw error when base set is not a set",
presetValues: map[string]interface{}{
"key9": "Default value",
"key10": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven"}),
"key11": set.NewSet([]string{"seven", "eight", "nine", "ten", "twelve"}),
},
keys: []string{"key9", "key10", "key11"},
want: nil,
wantErr: true,
},
{
name: "Throw error when base set is non-existent",
presetValues: map[string]interface{}{
"key12": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven"}),
"key13": set.NewSet([]string{"seven", "eight", "nine", "ten", "twelve"}),
},
keys: []string{"non-existent", "key7", "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)
}
}
})
}
}
func TestEchoVault_SDIFFSTORE(t *testing.T) {
server := createEchoVault()
tests := []struct {
name string
presetValues map[string]interface{}
destination string
keys []string
want int
wantErr bool
}{
{
name: "Get the difference between 2 sets",
presetValues: map[string]interface{}{
"key1": set.NewSet([]string{"one", "two", "three", "four", "five"}),
"key2": set.NewSet([]string{"three", "four", "five", "six", "seven", "eight"}),
},
destination: "destination1",
keys: []string{"key1", "key2"},
want: 2,
wantErr: false,
},
{
name: "Get the difference between 3 sets",
presetValues: map[string]interface{}{
"key3": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
"key4": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven"}),
"key5": set.NewSet([]string{"seven", "eight", "nine", "ten", "twelve"}),
},
destination: "destination2",
keys: []string{"key3", "key4", "key5"},
want: 4,
wantErr: false,
},
{
name: "Return base set element if base set is the only valid set",
presetValues: map[string]interface{}{
"key6": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
"key7": "Default value",
"key8": 123456789,
},
destination: "destination3",
keys: []string{"key6", "key7", "key8"},
want: 8,
wantErr: false,
},
{
name: "Throw error when base set is not a set",
presetValues: map[string]interface{}{
"key9": "Default value",
"key10": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven"}),
"key11": set.NewSet([]string{"seven", "eight", "nine", "ten", "twelve"}),
},
destination: "destination4",
keys: []string{"key9", "key10", "key11"},
want: 0,
wantErr: true,
},
{
name: " Throw error when base set is non-existent",
destination: "destination5",
presetValues: map[string]interface{}{
"key12": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven"}),
"key13": set.NewSet([]string{"seven", "eight", "nine", "ten", "twelve"}),
},
keys: []string{"non-existent", "key7", "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)
}
})
}
}
func TestEchoVault_SINTER(t *testing.T) {
server := createEchoVault()
tests := []struct {
name string
presetValues map[string]interface{}
keys []string
want []string
wantErr bool
}{
{
name: "Get the intersection between 2 sets",
presetValues: map[string]interface{}{
"key1": set.NewSet([]string{"one", "two", "three", "four", "five"}),
"key2": set.NewSet([]string{"three", "four", "five", "six", "seven", "eight"}),
},
keys: []string{"key1", "key2"},
want: []string{"three", "four", "five"},
wantErr: false,
},
{
name: "Get the intersection between 3 sets",
presetValues: map[string]interface{}{
"key3": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
"key4": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven", "eight"}),
"key5": set.NewSet([]string{"one", "eight", "nine", "ten", "twelve"}),
},
keys: []string{"key3", "key4", "key5"},
want: []string{"one", "eight"},
wantErr: false,
},
{
name: "Throw an error if any of the provided keys are not sets",
presetValues: map[string]interface{}{
"key6": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
"key7": "Default value",
"key8": set.NewSet([]string{"one"}),
},
keys: []string{"key6", "key7", "key8"},
want: nil,
wantErr: true,
},
{
name: "Throw error when base set is not a set",
presetValues: map[string]interface{}{
"key9": "Default value",
"key10": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven"}),
"key11": set.NewSet([]string{"seven", "eight", "nine", "ten", "twelve"}),
},
keys: []string{"key9", "key10", "key11"},
want: nil,
wantErr: true,
},
{
name: "If any of the keys does not exist, return an empty array",
presetValues: map[string]interface{}{
"key12": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven"}),
"key13": set.NewSet([]string{"seven", "eight", "nine", "ten", "twelve"}),
},
keys: []string{"non-existent", "key12", "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)
}
}
})
}
}
func TestEchoVault_SINTERCARD(t *testing.T) {
server := createEchoVault()
tests := []struct {
name string
presetValues map[string]interface{}
keys []string
limit uint
want int
wantErr bool
}{
{
name: "Get the full intersect cardinality between 2 sets",
presetValues: map[string]interface{}{
"key1": set.NewSet([]string{"one", "two", "three", "four", "five"}),
"key2": set.NewSet([]string{"three", "four", "five", "six", "seven", "eight"}),
},
keys: []string{"key1", "key2"},
limit: 0,
want: 3,
wantErr: false,
},
{
name: "Get an intersect cardinality between 2 sets with a limit",
presetValues: map[string]interface{}{
"key3": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"}),
"key4": set.NewSet([]string{"three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve"}),
},
keys: []string{"key3", "key4"},
limit: 3,
want: 3,
wantErr: false,
},
{
name: "Get the full intersect cardinality between 3 sets",
presetValues: map[string]interface{}{
"key5": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
"key6": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven", "eight"}),
"key7": set.NewSet([]string{"one", "seven", "eight", "nine", "ten", "twelve"}),
},
keys: []string{"key5", "key6", "key7"},
limit: 0,
want: 2,
wantErr: false,
},
{
name: "Get the intersection of 3 sets with a limit",
presetValues: map[string]interface{}{
"key8": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
"key9": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven", "eight"}),
"key10": set.NewSet([]string{"one", "two", "seven", "eight", "nine", "ten", "twelve"}),
},
keys: []string{"key8", "key9", "key10"},
limit: 2,
want: 2,
wantErr: false,
},
{
name: "Return error if any of the keys is non-existent",
presetValues: map[string]interface{}{
"key11": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
"key13": set.NewSet([]string{"one"}),
},
keys: []string{"key11", "key12", "key13"},
limit: 0,
want: 0,
wantErr: false,
},
{
name: "Throw error when one of the keys is not a valid set",
presetValues: map[string]interface{}{
"key14": "Default value",
"key15": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven"}),
"key16": set.NewSet([]string{"seven", "eight", "nine", "ten", "twelve"}),
},
keys: []string{"key14", "key15", "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)
}
})
}
}
func TestEchoVault_SINTERSTORE(t *testing.T) {
server := createEchoVault()
tests := []struct {
name string
presetValues map[string]interface{}
destination string
keys []string
want int
wantErr bool
}{
{
name: "Get the intersection between 2 sets and store it at the destination",
presetValues: map[string]interface{}{
"key1": set.NewSet([]string{"one", "two", "three", "four", "five"}),
"key2": set.NewSet([]string{"three", "four", "five", "six", "seven", "eight"}),
},
destination: "destination1",
keys: []string{"key1", "key2"},
want: 3,
wantErr: false,
},
{
name: "Get the intersection between 3 sets and store it at the destination key",
presetValues: map[string]interface{}{
"key3": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
"key4": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven", "eight"}),
"key5": set.NewSet([]string{"one", "seven", "eight", "nine", "ten", "twelve"}),
},
destination: "destination2",
keys: []string{"key3", "key4", "key5"},
want: 2,
wantErr: false,
},
{
name: "Throw error when any of the keys is not a set",
presetValues: map[string]interface{}{
"key6": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
"key7": "Default value",
"key8": set.NewSet([]string{"one"}),
},
destination: "destination3",
keys: []string{"key6", "key7", "key8"},
want: 0,
wantErr: true,
},
{
name: "Throw error when base set is not a set",
presetValues: map[string]interface{}{
"key9": "Default value",
"key10": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven"}),
"key11": set.NewSet([]string{"seven", "eight", "nine", "ten", "twelve"}),
},
destination: "destination4",
keys: []string{"key9", "key10", "key11"},
want: 0,
wantErr: true,
},
{
name: "Return an empty intersection if one of the keys does not exist",
destination: "destination5",
presetValues: map[string]interface{}{
"key12": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven"}),
"key13": set.NewSet([]string{"seven", "eight", "nine", "ten", "twelve"}),
},
keys: []string{"non-existent", "key12", "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)
}
})
}
}
func TestEchoVault_SISMEMBER(t *testing.T) {
server := createEchoVault()
tests := []struct {
name string
presetValue interface{}
key string
member string
want bool
wantErr bool
}{
{
name: "Return true when element is a member of the set",
presetValue: set.NewSet([]string{"one", "two", "three", "four"}),
key: "key1",
member: "three",
want: true,
wantErr: false,
},
{
name: "Return false when element is not a member of the set",
presetValue: set.NewSet([]string{"one", "two", "three", "four"}),
key: "key2",
member: "five",
want: false,
wantErr: false,
},
{
name: "Throw error when trying to assert membership when the key does not hold a valid set",
presetValue: "Default value",
key: "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)
}
})
}
}
func TestEchoVault_SMEMBERS(t *testing.T) {
server := createEchoVault()
tests := []struct {
name string
presetValue interface{}
key string
want []string
wantErr bool
}{
{
name: "Return all the members of the set",
key: "key1",
presetValue: set.NewSet([]string{"one", "two", "three", "four", "five"}),
want: []string{"one", "two", "three", "four", "five"},
wantErr: false,
},
{
name: "If the key does not exist, return an empty array",
key: "key2",
presetValue: nil,
want: []string{},
wantErr: false,
},
{
name: "Throw error when the provided key is not a set",
key: "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)
}
}
})
}
}
func TestEchoVault_SMISMEMBER(t *testing.T) {
server := createEchoVault()
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: "Return set membership status for multiple elements",
presetValue: set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven"}),
key: "key1",
members: []string{"three", "four", "five", "six", "eight", "nine", "seven"},
want: []bool{true, true, true, true, false, false, true},
wantErr: false,
},
{
name: "If the set key does not exist, return an array of zeroes as long as the list of members",
presetValue: nil,
key: "key2",
members: []string{"one", "two", "three", "four"},
want: []bool{false, false, false, false},
wantErr: false,
},
{
name: "Throw error when trying to assert membership when the key does not hold a valid set",
presetValue: "Default value",
key: "key3",
members: []string{"one"},
want: nil,
wantErr: true,
},
{
name: "Throw error for empty member slice",
presetValue: nil,
key: "key4",
members: []string{},
want: nil,
wantErr: true,
},
{
name: "Throw error for nil member slice",
presetValue: nil,
key: "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)
}
})
}
}
func TestEchoVault_SMOVE(t *testing.T) {
server := createEchoVault()
tests := []struct {
name string
presetValues map[string]interface{}
source string
destination string
member string
want bool
wantErr bool
}{
{
name: "Return true after a successful move of a member from source set to destination set",
presetValues: map[string]interface{}{
"source1": set.NewSet([]string{"one", "two", "three", "four"}),
"destination1": set.NewSet([]string{"five", "six", "seven", "eight"}),
},
source: "source1",
destination: "destination1",
member: "four",
want: true,
wantErr: false,
},
{
name: "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{}{
"source2": set.NewSet([]string{"one", "two", "three", "four", "five"}),
"destination2": set.NewSet([]string{"five", "six", "seven", "eight"}),
},
source: "source2",
destination: "destination2",
member: "six",
want: false,
wantErr: false,
},
{
name: "Return error when the source key is not a set",
presetValues: map[string]interface{}{
"source3": "Default value",
"destination3": set.NewSet([]string{"five", "six", "seven", "eight"}),
},
source: "source3",
destination: "destination3",
member: "five",
want: false,
wantErr: true,
},
{
name: "Return error when the destination key is not a set",
presetValues: map[string]interface{}{
"source4": set.NewSet([]string{"one", "two", "three", "four", "five"}),
"destination4": "Default value",
},
source: "source4",
destination: "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)
}
})
}
}
func TestEchoVault_SPOP(t *testing.T) {
server := createEchoVault()
tests := []struct {
name string
presetValue interface{}
key string
count uint
want []string
wantErr bool
}{
{
name: "Return multiple popped elements and modify the set",
key: "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: "Return error when the source key is not a set",
key: "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)
}
}
})
}
}
func TestEchoVault_SRANDMEMBER(t *testing.T) {
server := createEchoVault()
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: "Return multiple random elements without removing them",
key: "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: "Return multiple random elements without removing them",
key: "key2",
presetValue: set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
count: -5,
wantCount: 5,
wantErr: false,
},
{
name: "Return error when the source key is not a set",
key: "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())
}
}
})
}
}
func TestEchoVault_SREM(t *testing.T) {
server := createEchoVault()
tests := []struct {
name string
presetValue interface{}
key string
members []string
want int
wantErr bool
}{
{
name: "Remove multiple elements and return the number of elements removed",
key: "key1",
presetValue: set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
members: []string{"one", "two", "three", "nine"},
want: 3,
wantErr: false,
},
{
name: "If key does not exist, return 0",
key: "key2",
presetValue: nil,
members: []string{"one", "two", "three", "nine"},
want: 0,
wantErr: false,
},
{
name: "Return error when the source key is not a set",
key: "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)
}
})
}
}
func TestEchoVault_SUNION(t *testing.T) {
server := createEchoVault()
tests := []struct {
name string
presetValues map[string]interface{}
keys []string
want []string
wantErr bool
}{
{
name: "Get the union between 2 sets",
presetValues: map[string]interface{}{
"key1": set.NewSet([]string{"one", "two", "three", "four", "five"}),
"key2": set.NewSet([]string{"three", "four", "five", "six", "seven", "eight"}),
},
keys: []string{"key1", "key2"},
want: []string{"one", "two", "three", "four", "five", "six", "seven", "eight"},
wantErr: false,
},
{
name: "Get the union between 3 sets",
presetValues: map[string]interface{}{
"key3": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
"key4": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven", "eight"}),
"key5": set.NewSet([]string{"one", "eight", "nine", "ten", "twelve"}),
},
keys: []string{"key3", "key4", "key5"},
want: []string{
"one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
"ten", "eleven", "twelve", "thirty-six",
},
wantErr: false,
},
{
name: "Throw an error if any of the provided keys are not sets",
presetValues: map[string]interface{}{
"key6": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
"key7": "Default value",
"key8": set.NewSet([]string{"one"}),
},
keys: []string{"key6", "key7", "key8"},
want: nil,
wantErr: true,
},
{
name: "Throw error any of the keys does not hold a set",
presetValues: map[string]interface{}{
"key9": "Default value",
"key10": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven"}),
"key11": set.NewSet([]string{"seven", "eight", "nine", "ten", "twelve"}),
},
keys: []string{"key9", "key10", "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)
}
}
})
}
}
func TestEchoVault_SUNIONSTORE(t *testing.T) {
server := createEchoVault()
tests := []struct {
name string
presetValues map[string]interface{}
destination string
keys []string
want int
wantErr bool
}{
{
name: "Get the intersection between 2 sets and store it at the destination",
presetValues: map[string]interface{}{
"key1": set.NewSet([]string{"one", "two", "three", "four", "five"}),
"key2": set.NewSet([]string{"three", "four", "five", "six", "seven", "eight"}),
},
destination: "destination1",
keys: []string{"key1", "key2"},
want: 8,
wantErr: false,
},
{
name: "Get the intersection between 3 sets and store it at the destination key",
presetValues: map[string]interface{}{
"key3": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
"key4": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven", "eight"}),
"key5": set.NewSet([]string{"one", "seven", "eight", "nine", "ten", "twelve"}),
},
destination: "destination2",
keys: []string{"key3", "key4", "key5"},
want: 13,
wantErr: false,
},
{
name: "Throw error when any of the keys is not a set",
presetValues: map[string]interface{}{
"key6": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}),
"key7": "Default value",
"key8": set.NewSet([]string{"one"}),
},
destination: "destination3",
keys: []string{"key6", "key7", "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)
}
})
}
}