diff --git a/src/modules/sorted_set/commands.go b/src/modules/sorted_set/commands.go index 6cfa929..ce4368c 100644 --- a/src/modules/sorted_set/commands.go +++ b/src/modules/sorted_set/commands.go @@ -291,7 +291,7 @@ func handleZLEXCOUNT(ctx context.Context, cmd []string, server utils.Server, con for _, m := range members { if slices.Contains([]int{1, 0}, compareLex(string(m.value), minimum)) && - slices.Contains([]int{-1, 0}, compareLex(string(m.value), maximum)) { + slices.Contains([]int{-1, 0}, compareLex(string(m.value), maximum)) { count += 1 } } @@ -1042,7 +1042,7 @@ func handleZREMRANGEBYRANK(ctx context.Context, cmd []string, server utils.Serve stop = stop + set.Cardinality() } - if start < 0 || start > set.Cardinality()-1 || stop < 0 || start > set.Cardinality()-1 { + if start < 0 || start > set.Cardinality()-1 || stop < 0 || stop > set.Cardinality()-1 { return nil, errors.New("indices out of bounds") } @@ -1106,7 +1106,7 @@ func handleZREMRANGEBYLEX(ctx context.Context, cmd []string, server utils.Server // All the members have the same score for _, m := range members { if slices.Contains([]int{1, 0}, compareLex(string(m.value), minimum)) && - slices.Contains([]int{-1, 0}, compareLex(string(m.value), maximum)) { + slices.Contains([]int{-1, 0}, compareLex(string(m.value), maximum)) { set.Remove(m.value) deletedCount += 1 } @@ -1239,7 +1239,7 @@ func handleZRANGE(ctx context.Context, cmd []string, server utils.Server, conn * continue } if slices.Contains([]int{1, 0}, compareLex(string(members[i].value), lexStart)) && - slices.Contains([]int{-1, 0}, compareLex(string(members[i].value), lexStop)) { + slices.Contains([]int{-1, 0}, compareLex(string(members[i].value), lexStop)) { resultMembers = append(resultMembers, members[i]) } } @@ -1379,7 +1379,7 @@ func handleZRANGESTORE(ctx context.Context, cmd []string, server utils.Server, c continue } if slices.Contains([]int{1, 0}, compareLex(string(members[i].value), lexStart)) && - slices.Contains([]int{-1, 0}, compareLex(string(members[i].value), lexStop)) { + slices.Contains([]int{-1, 0}, compareLex(string(members[i].value), lexStop)) { resultMembers = append(resultMembers, members[i]) } } diff --git a/src/modules/sorted_set/commands_test.go b/src/modules/sorted_set/commands_test.go index f3a4895..7804dcd 100644 --- a/src/modules/sorted_set/commands_test.go +++ b/src/modules/sorted_set/commands_test.go @@ -2230,7 +2230,165 @@ func Test_HandleZREMRANGEBYSCORE(t *testing.T) { } } -func Test_HandleZREMRANGEBYRANK(t *testing.T) {} +func Test_HandleZREMRANGEBYRANK(t *testing.T) { + mockServer := server.NewServer(server.Opts{}) + + tests := []struct { + preset bool + presetValues map[string]interface{} + command []string + expectedValues map[string]*SortedSet + expectedResponse int + expectedError error + }{ + { // 1. Successfully remove multiple elements within range + preset: true, + presetValues: map[string]interface{}{ + "key1": NewSortedSet([]MemberParam{ + {value: "one", score: 1}, {value: "two", score: 2}, + {value: "three", score: 3}, {value: "four", score: 4}, + {value: "five", score: 5}, {value: "six", score: 6}, + {value: "seven", score: 7}, {value: "eight", score: 8}, + {value: "nine", score: 9}, {value: "ten", score: 10}, + }), + }, + command: []string{"ZREMRANGEBYRANK", "key1", "0", "5"}, + expectedValues: map[string]*SortedSet{ + "key1": NewSortedSet([]MemberParam{ + {value: "seven", score: 7}, {value: "eight", score: 8}, + {value: "nine", score: 9}, {value: "ten", score: 10}, + }), + }, + expectedResponse: 6, + expectedError: nil, + }, + { // 2. Establish boundaries from the end of the set when negative boundaries are provided + preset: true, + presetValues: map[string]interface{}{ + "key2": NewSortedSet([]MemberParam{ + {value: "one", score: 1}, {value: "two", score: 2}, + {value: "three", score: 3}, {value: "four", score: 4}, + {value: "five", score: 5}, {value: "six", score: 6}, + {value: "seven", score: 7}, {value: "eight", score: 8}, + {value: "nine", score: 9}, {value: "ten", score: 10}, + }), + }, + command: []string{"ZREMRANGEBYRANK", "key2", "-6", "-3"}, + expectedValues: map[string]*SortedSet{ + "key2": NewSortedSet([]MemberParam{ + {value: "one", score: 1}, {value: "two", score: 2}, + {value: "three", score: 3}, {value: "four", score: 4}, + {value: "nine", score: 9}, {value: "ten", score: 10}, + }), + }, + expectedResponse: 4, + expectedError: nil, + }, + { // 2. If key does not exist, return 0 + preset: false, + presetValues: nil, + command: []string{"ZREMRANGEBYRANK", "key3", "2", "4"}, + expectedValues: nil, + expectedResponse: 0, + expectedError: nil, + }, + { // 3. Return error key is not a sorted set + preset: true, + presetValues: map[string]interface{}{ + "key3": "Default value", + }, + command: []string{"ZREMRANGEBYRANK", "key3", "4", "4"}, + expectedError: errors.New("value at key3 is not a sorted set"), + }, + { // 4. Command too short + preset: false, + command: []string{"ZREMRANGEBYRANK", "key4", "3"}, + expectedError: errors.New(utils.WRONG_ARGS_RESPONSE), + }, + { // 5. Return error when start index is out of bounds + preset: true, + presetValues: map[string]interface{}{ + "key5": NewSortedSet([]MemberParam{ + {value: "one", score: 1}, {value: "two", score: 2}, + {value: "three", score: 3}, {value: "four", score: 4}, + {value: "five", score: 5}, {value: "six", score: 6}, + {value: "seven", score: 7}, {value: "eight", score: 8}, + {value: "nine", score: 9}, {value: "ten", score: 10}, + }), + }, + command: []string{"ZREMRANGEBYRANK", "key5", "-12", "5"}, + expectedValues: nil, + expectedResponse: 0, + expectedError: errors.New("indices out of bounds"), + }, + { // 6. Return error when end index is out of bounds + preset: true, + presetValues: map[string]interface{}{ + "key6": NewSortedSet([]MemberParam{ + {value: "one", score: 1}, {value: "two", score: 2}, + {value: "three", score: 3}, {value: "four", score: 4}, + {value: "five", score: 5}, {value: "six", score: 6}, + {value: "seven", score: 7}, {value: "eight", score: 8}, + {value: "nine", score: 9}, {value: "ten", score: 10}, + }), + }, + command: []string{"ZREMRANGEBYRANK", "key6", "0", "11"}, + expectedValues: nil, + expectedResponse: 0, + expectedError: errors.New("indices out of bounds"), + }, + { // 7. Command too long + preset: false, + command: []string{"ZREMRANGEBYRANK", "key7", "4", "5", "8"}, + expectedError: errors.New(utils.WRONG_ARGS_RESPONSE), + }, + } + + for _, test := range tests { + if test.preset { + for key, value := range test.presetValues { + if _, err := mockServer.CreateKeyAndLock(context.Background(), key); err != nil { + t.Error(err) + } + mockServer.SetValue(context.Background(), key, value) + mockServer.KeyUnlock(key) + } + } + res, err := handleZREMRANGEBYRANK(context.Background(), test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + continue + } + if err != nil { + t.Error(err) + } + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) + } + if rv.Integer() != test.expectedResponse { + t.Errorf("expected response %d, got %d", test.expectedResponse, rv.Integer()) + } + // Check if the expected values are the same + if test.expectedValues != nil { + for key, expectedSet := range test.expectedValues { + if _, err = mockServer.KeyRLock(context.Background(), key); err != nil { + t.Error(err) + } + set, ok := mockServer.GetValue(key).(*SortedSet) + if !ok { + t.Errorf("expected value at key \"%s\" to be a sorted set, got another type", key) + } + if !set.Equals(expectedSet) { + t.Errorf("exptected sorted set %+v, got %+v", expectedSet, set) + } + } + } + } +} func Test_HandleZREMRANGEBYLEX(t *testing.T) { mockServer := server.NewServer(server.Opts{})