Skip to content

Commit

Permalink
few more tests for HRANDFIELD
Browse files Browse the repository at this point in the history
  • Loading branch information
alicebob committed Dec 12, 2023
1 parent 794a09d commit 422ad09
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 31 deletions.
74 changes: 44 additions & 30 deletions cmd_hash.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package miniredis

import (
"math/big"
"math/rand"
"strconv"
"strings"

Expand Down Expand Up @@ -700,16 +701,17 @@ func (m *Miniredis) cmdHrandfield(c *server.Peer, cmd string, args []string) {
opts := struct {
key string
count int
countSet bool
withValues bool
}{
key: args[0],
count: 1,
key: args[0],
}

if len(args) > 1 {
if ok := optIntErr(c, args[1], &opts.count, msgInvalidInt); !ok {
return
}
opts.countSet = true
}

if len(args) == 3 {
Expand All @@ -723,42 +725,54 @@ func (m *Miniredis) cmdHrandfield(c *server.Peer, cmd string, args []string) {
}

withTx(m, c, func(peer *server.Peer, ctx *connCtx) {
if opts.count == 0 {
peer.WriteLen(0)
return
}
db := m.db(ctx.selectedDB)
members := db.hashFields(opts.key)
// if cnt positive
cnt := 0
iterCnt := len(members)
if opts.count > 0 {
if opts.count > len(members) {
cnt = len(members)
} else {
cnt = opts.count
m.shuffle(members)

if !opts.countSet {
// > When called with just the key argument, return a random field from the
// hash value stored at key.
if len(members) == 0 {
peer.WriteNull()
return
}
} else {
cnt = -opts.count
iterCnt *= cnt
peer.WriteBulk(members[0])
return
}

p := m.randPerm(iterCnt)
if opts.withValues {
peer.WriteMapLen(cnt)
for i := 0; i < cnt; i++ {
idx := p[i] % len(members)
peer.WriteBulk(members[idx])
peer.WriteBulk(db.hashGet(opts.key, members[idx]))
if len(members) > abs(opts.count) {
members = members[:abs(opts.count)]
}
switch {
case opts.count >= 0:
// if count is positive there can't be duplicates, and the length is restricted
case opts.count < 0:
// if count is negative there can be duplicates, but length will match
if len(members) > 0 {
for len(members) < -opts.count {
members = append(members, members[rand.Intn(len(members))])
}
}
return
} else {
peer.WriteLen(cnt)
for i := 0; i < cnt; i++ {
idx := p[i] % len(members)
peer.WriteBulk(members[idx])
}

if opts.withValues {
peer.WriteMapLen(len(members))
for _, m := range members {
peer.WriteBulk(m)
peer.WriteBulk(db.hashGet(opts.key, m))
}
return
}
peer.WriteLen(len(members))
for _, m := range members {
peer.WriteBulk(m)
}
})
}

func abs(n int) int {
if n < 0 {
return -n
}
return n
}
32 changes: 31 additions & 1 deletion integration/hash_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,10 +233,40 @@ func TestHstrlen(t *testing.T) {
func TestHrandfield(t *testing.T) {
skip(t)
testRaw(t, func(c *client) {
// A random key from a DB with a single key. We can test that.
c.Do("HSET", "one", "foo", "bar")
c.Do("HRANDFIELD", "one")
c.Do("HRANDFIELD", "one", "0")
c.Do("HRANDFIELD", "one", "1")
c.Do("HRANDFIELD", "one", "2") // limited to 1
c.Do("HRANDFIELD", "one", "3") // limited to 1
c.Do("HRANDFIELD", "one", "-1")
c.Do("HRANDFIELD", "one", "-2") // padded
c.Do("HRANDFIELD", "one", "-3") // padded

c.Do("HSET", "more", "foo", "bar", "baz", "bak")
c.DoLoosely("HRANDFIELD", "more")
c.Do("HRANDFIELD", "more", "0")
c.DoLoosely("HRANDFIELD", "more", "1")
c.DoLoosely("HRANDFIELD", "more", "2")
c.DoLoosely("HRANDFIELD", "more", "3") // limited to 2
c.DoLoosely("HRANDFIELD", "more", "-1")
c.DoLoosely("HRANDFIELD", "more", "-2")
c.DoLoosely("HRANDFIELD", "more", "-3") // length padded to 3

c.Do("HRANDFIELD", "nosuch", "1")
c.Do("HRANDFIELD", "nosuch", "2")
c.Do("HRANDFIELD", "nosuch", "3")
c.Do("HRANDFIELD", "nosuch", "0")
c.Do("HRANDFIELD", "nosuch")
c.Do("HRANDFIELD", "nosuch", "-1") // still empty
c.Do("HRANDFIELD", "nosuch", "-2") // still empty
c.Do("HRANDFIELD", "nosuch", "-3") // still empty
c.DoLoosely("HRANDFIELD", "one", "2")
c.DoLoosely("HRANDFIELD", "one", "7")
c.DoLoosely("HRANDFIELD", "one", "2", "WITHVALUE")
c.DoLoosely("HRANDFIELD", "one", "7", "WITHVALUE")

c.Error("ERR syntax error", "HRANDFIELD", "foo", "1", "2")
c.Error("ERR wrong number", "HRANDFIELD")
})
}

0 comments on commit 422ad09

Please sign in to comment.