You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kvrocks.apache.org by ti...@apache.org on 2022/09/27 15:31:12 UTC

[incubator-kvrocks] branch unstable updated: Move TCL test unit/type/hash to Go case (#903)

This is an automated email from the ASF dual-hosted git repository.

tison pushed a commit to branch unstable
in repository https://gitbox.apache.org/repos/asf/incubator-kvrocks.git


The following commit(s) were added to refs/heads/unstable by this push:
     new da0d776  Move TCL test unit/type/hash to Go case (#903)
da0d776 is described below

commit da0d77680a8cf0ef678c1e1c8debea0f7dffdee3
Author: IoCing <39...@users.noreply.github.com>
AuthorDate: Tue Sep 27 23:31:07 2022 +0800

    Move TCL test unit/type/hash to Go case (#903)
    
    Co-authored-by: hulk <hu...@gmail.com>
    Co-authored-by: tison <wa...@gmail.com>
---
 tests/gocase/unit/type/hash/hash_test.go | 654 +++++++++++++++++++++++++++++--
 tests/gocase/util/random.go              |   4 +-
 tests/tcl/tests/test_helper.tcl          |   1 -
 tests/tcl/tests/unit/type/hash.tcl       | 528 -------------------------
 4 files changed, 619 insertions(+), 568 deletions(-)

diff --git a/tests/gocase/unit/type/hash/hash_test.go b/tests/gocase/unit/type/hash/hash_test.go
index 349f88b..8ffb6a8 100644
--- a/tests/gocase/unit/type/hash/hash_test.go
+++ b/tests/gocase/unit/type/hash/hash_test.go
@@ -21,67 +21,647 @@ package hash
 
 import (
 	"context"
+	"errors"
+	"fmt"
+	"sort"
+	"strconv"
+	"strings"
 	"testing"
+	"time"
 
 	"github.com/apache/incubator-kvrocks/tests/gocase/util"
 	"github.com/stretchr/testify/require"
 )
 
+func getKeys(hash map[string]string) []string {
+	r := make([]string, 0)
+	for key := range hash {
+		r = append(r, key)
+	}
+	return r
+}
+
+func getVals(hash map[string]string) []string {
+	r := make([]string, 0)
+	for _, val := range hash {
+		r = append(r, val)
+	}
+	return r
+}
+
 func TestHash(t *testing.T) {
 	srv := util.StartServer(t, map[string]string{})
 	defer srv.Close()
 	ctx := context.Background()
 	rdb := srv.NewClient()
 	defer func() { require.NoError(t, rdb.Close()) }()
-	kvArray := []string{"a", "a", "b", "b", "c", "c", "d", "d", "e", "e", "key1", "value1", "key2", "value2", "key3", "value3", "key10", "value10", "z", "z", "x", "x"}
-	t.Run("HRange normal situation ", func(t *testing.T) {
-		require.NoError(t, rdb.Del(ctx, "hashkey").Err())
-		require.NoError(t, rdb.HMSet(ctx, "hashkey", kvArray).Err())
-		require.EqualValues(t, []interface{}{"key1", "value1", "key10", "value10"}, rdb.Do(ctx, "HRange", "hashkey", "key1", "key2", "limit", 100).Val())
-		require.EqualValues(t, []interface{}{"key1", "value1", "key10", "value10", "key2", "value2"}, rdb.Do(ctx, "HRange", "hashkey", "key1", "key3", "limit", 100).Val())
+	smallhash := make(map[string]string)
+	bighash := make(map[string]string)
+
+	t.Run("HSET/HLEN - Small hash creation", func(t *testing.T) {
+		for i := 0; i < 8; i++ {
+			key := "__avoid_collisions__" + util.RandString(0, 8, util.Alpha)
+			val := "__avoid_collisions__" + util.RandString(0, 8, util.Alpha)
+			if _, ok := smallhash[key]; ok {
+				i--
+			}
+			rdb.HSet(ctx, "smallhash", key, val)
+			smallhash[key] = val
+		}
+		require.Equal(t, int64(8), rdb.HLen(ctx, "smallhash").Val())
+	})
+
+	t.Run("HSET/HLEN - Big hash creation", func(t *testing.T) {
+		for i := 0; i < 1024; i++ {
+			key := "__avoid_collisions__" + util.RandString(0, 8, util.Alpha)
+			val := "__avoid_collisions__" + util.RandString(0, 8, util.Alpha)
+			if _, ok := bighash[key]; ok {
+				i--
+			}
+			rdb.HSet(ctx, "bighash", key, val)
+			bighash[key] = val
+		}
+		require.Equal(t, int64(1024), rdb.HLen(ctx, "bighash").Val())
+	})
+
+	t.Run("HSET wrong number of args", func(t *testing.T) {
+		pattern := ".*wrong number.*"
+		util.ErrorRegexp(t, rdb.HSet(ctx, "hmsetmulti", "key1", "val1", "key2").Err(), pattern)
+	})
+
+	t.Run("HSET supports multiple fields", func(t *testing.T) {
+		require.Equal(t, int64(2), rdb.HSet(ctx, "hmsetmulti", "key1", "val1", "key2", "val2").Val())
+		require.Equal(t, int64(0), rdb.HSet(ctx, "hmsetmulti", "key1", "val1", "key2", "val2").Val())
+		require.Equal(t, int64(1), rdb.HSet(ctx, "hmsetmulti", "key1", "val1", "key3", "val3").Val())
+	})
+
+	t.Run("HGET against the small hash", func(t *testing.T) {
+		var err error
+		for key, val := range smallhash {
+			res := rdb.HGet(ctx, "smallhash", key)
+			if val != res.Val() {
+				err = res.Err()
+				break
+			}
+		}
+		require.NoError(t, err)
+	})
+
+	t.Run("HGET against the big hash", func(t *testing.T) {
+		var err error
+		for key, val := range bighash {
+			res := rdb.HGet(ctx, "bighash", key)
+			if val != res.Val() {
+				err = res.Err()
+				break
+			}
+		}
+		require.NoError(t, err)
+	})
+
+	t.Run("HGET against non existing key", func(t *testing.T) {
+		var rv []string
+		rv = append(rv, rdb.HGet(ctx, "samllhash", "__123123123__").Val())
+		rv = append(rv, rdb.HGet(ctx, "bighash", "__123123123__").Val())
+		require.Equal(t, []string{"", ""}, rv)
+	})
+
+	t.Run("HSET in update and insert mode", func(t *testing.T) {
+		var rv []string
+		k := getKeys(smallhash)[0]
+		rv = append(rv, fmt.Sprintf("%d", rdb.HSet(ctx, "smallhash", k, "newval1").Val()))
+		smallhash[k] = "newval1"
+		rv = append(rv, rdb.HGet(ctx, "smallhash", k).Val())
+		rv = append(rv, fmt.Sprintf("%d", rdb.HSet(ctx, "smallhash", "__foobar123__", "newval").Val()))
+		k = getKeys(bighash)[0]
+		rv = append(rv, fmt.Sprintf("%d", rdb.HSet(ctx, "bighash", k, "newval2").Val()))
+		bighash[k] = "newval2"
+		rv = append(rv, rdb.HGet(ctx, "bighash", k).Val())
+		rv = append(rv, fmt.Sprintf("%d", rdb.HSet(ctx, "bighash", "__foobar123__", "newval").Val()))
+		rv = append(rv, fmt.Sprintf("%d", rdb.HDel(ctx, "smallhash", "__foobar123__").Val()))
+		rv = append(rv, fmt.Sprintf("%d", rdb.HDel(ctx, "bighash", "__foobar123__").Val()))
+		require.Equal(t, []string{"0", "newval1", "1", "0", "newval2", "1", "1", "1"}, rv)
+	})
+
+	t.Run("HSETNX target key missing - small hash", func(t *testing.T) {
+		rdb.HSetNX(ctx, "smallhash", "__123123123__", "foo")
+		require.Equal(t, "foo", rdb.HGet(ctx, "smallhash", "__123123123__").Val())
+	})
+
+	t.Run("HSETNX target key exists - small hash", func(t *testing.T) {
+		rdb.HSetNX(ctx, "smallhash", "__123123123__", "bar")
+		res := rdb.HGet(ctx, "smallhash", "__123123123__").Val()
+		rdb.HDel(ctx, "smallhash", "__123123123__")
+		require.Equal(t, "foo", res)
+	})
+
+	t.Run("HSETNX target key missing - big hash", func(t *testing.T) {
+		rdb.HSetNX(ctx, "bighash", "__123123123__", "foo")
+		require.Equal(t, "foo", rdb.HGet(ctx, "bighash", "__123123123__").Val())
+	})
+
+	t.Run("HSETNX target key exists - big hash", func(t *testing.T) {
+		rdb.HSetNX(ctx, "bighash", "__123123123__", "bar")
+		res := rdb.HGet(ctx, "bighash", "__123123123__").Val()
+		rdb.HDel(ctx, "bighash", "__123123123__")
+		require.Equal(t, "foo", res)
+	})
+
+	t.Run("HMSET wrong number of args", func(t *testing.T) {
+		pattern := ".*wrong number.*"
+		util.ErrorRegexp(t, rdb.HMSet(ctx, "smallhash", "key1", "val1", "key2").Err(), pattern)
+	})
+
+	t.Run("HMSET - small hash", func(t *testing.T) {
+		var args []string
+		for key := range smallhash {
+			newval := util.RandString(0, 8, util.Alpha)
+			smallhash[key] = newval
+			args = append(args, key, newval)
+		}
+		require.Equal(t, true, rdb.HMSet(ctx, "smallhash", args).Val())
+	})
+
+	t.Run("HMSET - big hash", func(t *testing.T) {
+		var args []string
+		for key := range bighash {
+			newval := util.RandString(0, 8, util.Alpha)
+			bighash[key] = newval
+			args = append(args, key, newval)
+		}
+		require.Equal(t, true, rdb.HMSet(ctx, "bighash", args).Val())
+	})
+
+	t.Run("HMGET against non existing key and fields", func(t *testing.T) {
+		var rv [][]interface{}
+		cmd1 := rdb.HMGet(ctx, "doesntexist", "__123123123__", "__456456456__")
+		rv = append(rv, cmd1.Val())
+		cmd2 := rdb.HMGet(ctx, "smallhash", "__123123123__", "__456456456__")
+		rv = append(rv, cmd2.Val())
+		cmd3 := rdb.HMGet(ctx, "bighash", "__123123123__", "__456456456__")
+		rv = append(rv, cmd3.Val())
+		require.Equal(t, [][]interface{}{{interface{}(nil), interface{}(nil)}, {interface{}(nil), interface{}(nil)}, {interface{}(nil), interface{}(nil)}}, rv)
+	})
+
+	t.Run("HMGET against wrong type", func(t *testing.T) {
+		rdb.Set(ctx, "wrongtype", "somevalue", time.Millisecond*1000)
+		pattern := ".*wrong.*"
+		util.ErrorRegexp(t, rdb.HMGet(ctx, "wrongtype", "field1", "field2").Err(), pattern)
+	})
+
+	t.Run("HMGET - small hash", func(t *testing.T) {
+		var keys []string
+		var vals []string
+		for key, val := range smallhash {
+			keys = append(keys, key)
+			vals = append(vals, val)
+		}
+		var err error
+		res := rdb.HMGet(ctx, "smallhash", keys...).Val()
+		for i := range vals {
+			if vals[i] != res[i].(string) {
+				err = errors.New("$vals != $result")
+				break
+			}
+		}
+		require.NoError(t, err)
+	})
+
+	t.Run("HMGET - big hash", func(t *testing.T) {
+		var keys []string
+		var vals []string
+		for key, val := range bighash {
+			keys = append(keys, key)
+			vals = append(vals, val)
+		}
+		var err error
+		res := rdb.HMGet(ctx, "bighash", keys...).Val()
+		for i := range vals {
+			if vals[i] != res[i].(string) {
+				err = errors.New("$vals != $result")
+				break
+			}
+		}
+		require.NoError(t, err)
+	})
+
+	t.Run("HKEYS - small hash}", func(t *testing.T) {
+		expect := getKeys(smallhash)
+		sort.Strings(expect)
+		actual := rdb.HKeys(ctx, "smallhash").Val()
+		sort.Strings(actual)
+		require.Equal(t, expect, actual)
+	})
+
+	t.Run("HKEYS - big hash}", func(t *testing.T) {
+		expect := getKeys(bighash)
+		sort.Strings(expect)
+		actual := rdb.HKeys(ctx, "bighash").Val()
+		sort.Strings(actual)
+		require.Equal(t, expect, actual)
+	})
+
+	t.Run("HVALS - small hash}", func(t *testing.T) {
+		expect := getVals(smallhash)
+		sort.Strings(expect)
+		actual := rdb.HVals(ctx, "smallhash").Val()
+		sort.Strings(actual)
+		require.Equal(t, expect, actual)
+	})
+
+	t.Run("HVALS - big hash}", func(t *testing.T) {
+		expect := getVals(bighash)
+		sort.Strings(expect)
+		actual := rdb.HVals(ctx, "bighash").Val()
+		sort.Strings(actual)
+		require.Equal(t, expect, actual)
+	})
+
+	t.Run("HGETALL - small hash}", func(t *testing.T) {
+		res := rdb.Do(ctx, "hgetall", "smallhash").Val().([]interface{})
+		mid := make(map[string]string)
+		for i := 0; i < len(res); i += 2 {
+			if res[i+1] == nil {
+				mid[res[i].(string)] = ""
+			} else {
+				mid[res[i].(string)] = res[i+1].(string)
+			}
+		}
+		require.Equal(t, smallhash, mid)
+	})
+
+	t.Run("HGETALL - big hash}", func(t *testing.T) {
+		res := rdb.Do(ctx, "hgetall", "bighash").Val().([]interface{})
+		mid := make(map[string]string)
+		for i := 0; i < len(res); i += 2 {
+			if res[i+1] == nil {
+				mid[res[i].(string)] = ""
+			} else {
+				mid[res[i].(string)] = res[i+1].(string)
+			}
+		}
+		require.Equal(t, bighash, mid)
+	})
+
+	t.Run("HDEL and return value", func(t *testing.T) {
+		var rv []string
+		rv = append(rv, fmt.Sprintf("%d", rdb.HDel(ctx, "smallhash", "nokey").Val()))
+		rv = append(rv, fmt.Sprintf("%d", rdb.HDel(ctx, "bighash", "nokey").Val()))
+		k := getKeys(smallhash)[0]
+		rv = append(rv, fmt.Sprintf("%d", rdb.HDel(ctx, "smallhash", k).Val()))
+		rv = append(rv, fmt.Sprintf("%d", rdb.HDel(ctx, "smallhash", k).Val()))
+		rv = append(rv, rdb.HGet(ctx, "smallhash", k).Val())
+		delete(smallhash, k)
+		k = getKeys(bighash)[0]
+		rv = append(rv, fmt.Sprintf("%d", rdb.HDel(ctx, "bighash", k).Val()))
+		rv = append(rv, fmt.Sprintf("%d", rdb.HDel(ctx, "bighash", k).Val()))
+		rv = append(rv, rdb.HGet(ctx, "bighash", k).Val())
+		delete(bighash, k)
+		require.Equal(t, []string{"0", "0", "1", "0", "", "1", "0", ""}, rv)
+	})
+
+	t.Run("HDEL - more than a single value", func(t *testing.T) {
+		rdb.Del(ctx, "myhash")
+		rdb.HMSet(ctx, "myhash", []string{"a", "1", "b", "2", "c", "3"})
+		require.Equal(t, int64(0), rdb.HDel(ctx, "myhash", "x", "y").Val())
+		require.Equal(t, int64(2), rdb.HDel(ctx, "myhash", "a", "c", "f").Val())
+		require.Equal(t, map[string]string{"b": "2"}, rdb.HGetAll(ctx, "myhash").Val())
+	})
+
+	t.Run("HDEL - hash becomes empty before deleting all specified fields", func(t *testing.T) {
+		rdb.Del(ctx, "myhash")
+		rdb.HMSet(ctx, "myhash", []string{"a", "1", "b", "2", "c", "3"})
+		require.Equal(t, int64(3), rdb.HDel(ctx, "myhash", "a", "b", "c", "d", "e").Val())
+		require.Equal(t, int64(0), rdb.Exists(ctx, "myhash").Val())
+	})
+
+	t.Run("HEXISTS", func(t *testing.T) {
+		var rv []bool
+		k := getKeys(smallhash)[0]
+		rv = append(rv, rdb.HExists(ctx, "smallhash", k).Val())
+		rv = append(rv, rdb.HExists(ctx, "smallhash", "nokey").Val())
+		k = getKeys(bighash)[0]
+		rv = append(rv, rdb.HExists(ctx, "bighash", k).Val())
+		rv = append(rv, rdb.HExists(ctx, "bighash", "nokey").Val())
+		require.Equal(t, []bool{true, false, true, false}, rv)
+	})
+
+	t.Run("HINCRBY against non existing database key", func(t *testing.T) {
+		rdb.Del(ctx, "htest")
+		require.Equal(t, int64(2), rdb.HIncrBy(ctx, "htest", "foo", 2).Val())
+	})
+
+	t.Run("HINCRBY against non existing hash key", func(t *testing.T) {
+		var rv []string
+		rdb.HDel(ctx, "smallhash", "tmp")
+		rdb.HDel(ctx, "bighash", "tmp")
+		rv = append(rv, fmt.Sprintf("%d", rdb.HIncrBy(ctx, "smallhash", "tmp", 2).Val()))
+		rv = append(rv, rdb.HGet(ctx, "smallhash", "tmp").Val())
+		rv = append(rv, fmt.Sprintf("%d", rdb.HIncrBy(ctx, "bighash", "tmp", 2).Val()))
+		rv = append(rv, rdb.HGet(ctx, "bighash", "tmp").Val())
+		require.Equal(t, []string{"2", "2", "2", "2"}, rv)
+	})
+
+	t.Run("HINCRBY against hash key created by hincrby itself", func(t *testing.T) {
+		var rv []string
+		rv = append(rv, fmt.Sprintf("%d", rdb.HIncrBy(ctx, "smallhash", "tmp", 3).Val()))
+		rv = append(rv, rdb.HGet(ctx, "smallhash", "tmp").Val())
+		rv = append(rv, fmt.Sprintf("%d", rdb.HIncrBy(ctx, "bighash", "tmp", 3).Val()))
+		rv = append(rv, rdb.HGet(ctx, "bighash", "tmp").Val())
+		require.Equal(t, []string{"5", "5", "5", "5"}, rv)
+	})
+
+	t.Run("HINCRBY against hash key originally set with HSET", func(t *testing.T) {
+		rdb.HSet(ctx, "smallhash", "tmp", "100")
+		rdb.HSet(ctx, "bighash", "tmp", "100")
+		require.Equal(t, []int64{102, 102},
+			[]int64{rdb.HIncrBy(ctx, "smallhash", "tmp", 2).Val(),
+				rdb.HIncrBy(ctx, "bighash", "tmp", 2).Val()})
+	})
+
+	t.Run("HINCRBY over 32bit value", func(t *testing.T) {
+		rdb.HSet(ctx, "smallhash", "tmp", "17179869184")
+		rdb.HSet(ctx, "bighash", "tmp", "17179869184")
+		require.Equal(t, []int64{17179869185, 17179869185},
+			[]int64{rdb.HIncrBy(ctx, "smallhash", "tmp", 1).Val(),
+				rdb.HIncrBy(ctx, "bighash", "tmp", 1).Val()})
+	})
+
+	t.Run("HINCRBY over 32bit value with over 32bit increment", func(t *testing.T) {
+		rdb.HSet(ctx, "smallhash", "tmp", "17179869184")
+		rdb.HSet(ctx, "bighash", "tmp", "17179869184")
+		require.Equal(t, []int64{34359738368, 34359738368},
+			[]int64{rdb.HIncrBy(ctx, "smallhash", "tmp", 17179869184).Val(),
+				rdb.HIncrBy(ctx, "bighash", "tmp", 17179869184).Val()})
+	})
+
+	t.Run("HINCRBY fails against hash value with spaces (left)", func(t *testing.T) {
+		rdb.HSet(ctx, "samllhash", "str", " 11")
+		rdb.HSet(ctx, "bighash", "str", " 11")
+		pattern := "ERR.*not an integer.*"
+		util.ErrorRegexp(t, rdb.HIncrBy(ctx, "samllhash", "str", 1).Err(), pattern)
+		util.ErrorRegexp(t, rdb.HIncrBy(ctx, "bighash", "str", 1).Err(), pattern)
+	})
+
+	t.Run("HINCRBY fails against hash value with spaces (right)", func(t *testing.T) {
+		rdb.HSet(ctx, "samllhash", "str", "11 ")
+		rdb.HSet(ctx, "bighash", "str", "11 ")
+		pattern := "ERR.*non-integer.*"
+		util.ErrorRegexp(t, rdb.HIncrBy(ctx, "samllhash", "str", 1).Err(), pattern)
+		util.ErrorRegexp(t, rdb.HIncrBy(ctx, "bighash", "str", 1).Err(), pattern)
+	})
+
+	t.Run("HINCRBY can detect overflows", func(t *testing.T) {
+		rdb.HSet(ctx, "hash", "n", "-9223372036854775484")
+		require.Equal(t, int64(-9223372036854775485), rdb.HIncrBy(ctx, "hash", "n", -1).Val())
+		pattern := ".*overflow.*"
+		util.ErrorRegexp(t, rdb.HIncrBy(ctx, "hash", "n", -10000).Err(), pattern)
+	})
+
+	t.Run("HINCRBYFLOAT against non existing database key", func(t *testing.T) {
+		rdb.Del(ctx, "htest")
+		require.Equal(t, 2.5, rdb.HIncrByFloat(ctx, "htest", "foo", 2.5).Val())
+	})
+
+	t.Run("HINCRBYFLOAT against non existing hash key", func(t *testing.T) {
+		var rv []float64
+		rdb.HDel(ctx, "smallhash", "tmp")
+		rdb.HDel(ctx, "bighash", "tmp")
+		rv = append(rv, rdb.HIncrByFloat(ctx, "smallhash", "tmp", 2.5).Val())
+		if res, err := strconv.ParseFloat(rdb.HGet(ctx, "smallhash", "tmp").Val(), strconv.IntSize); err == nil {
+			rv = append(rv, res)
+		}
+		rv = append(rv, rdb.HIncrByFloat(ctx, "bighash", "tmp", 2.5).Val())
+		if res, err := strconv.ParseFloat(rdb.HGet(ctx, "bighash", "tmp").Val(), strconv.IntSize); err == nil {
+			rv = append(rv, res)
+		}
+		require.Equal(t, []float64{2.5, 2.5, 2.5, 2.5}, rv)
+	})
+
+	t.Run("HINCRBYFLOAT against hash key created by hincrby itself", func(t *testing.T) {
+		var rv []float64
+		rv = append(rv, rdb.HIncrByFloat(ctx, "smallhash", "tmp", 3.5).Val())
+		if res, err := strconv.ParseFloat(rdb.HGet(ctx, "smallhash", "tmp").Val(), strconv.IntSize); err == nil {
+			rv = append(rv, res)
+		}
+		rv = append(rv, rdb.HIncrByFloat(ctx, "bighash", "tmp", 3.5).Val())
+		if res, err := strconv.ParseFloat(rdb.HGet(ctx, "bighash", "tmp").Val(), strconv.IntSize); err == nil {
+			rv = append(rv, res)
+		}
+		require.Equal(t, []float64{6, 6, 6, 6}, rv)
+	})
+
+	t.Run("HINCRBYFLOAT against hash key originally set with HSET", func(t *testing.T) {
+		var rv []float64
+		rdb.HSet(ctx, "smallhash", "tmp", 100)
+		rdb.HSet(ctx, "bighash", "tmp", 100)
+		rv = append(rv, rdb.HIncrByFloat(ctx, "smallhash", "tmp", 2.5).Val())
+		rv = append(rv, rdb.HIncrByFloat(ctx, "bighash", "tmp", 2.5).Val())
+		require.Equal(t, []float64{102.5, 102.5}, rv)
+	})
+
+	t.Run("HINCRBYFLOAT over 32bit value", func(t *testing.T) {
+		rdb.HSet(ctx, "smallhash", "tmp", "17179869184")
+		rdb.HSet(ctx, "bighash", "tmp", "17179869184")
+		require.Equal(t, []float64{17179869185, 17179869185},
+			[]float64{rdb.HIncrByFloat(ctx, "smallhash", "tmp", 1).Val(),
+				rdb.HIncrByFloat(ctx, "bighash", "tmp", 1).Val()})
+	})
+
+	t.Run("HINCRBYFLOAT over 32bit value with over 32bit increment", func(t *testing.T) {
+		rdb.HSet(ctx, "smallhash", "tmp", "17179869184")
+		rdb.HSet(ctx, "bighash", "tmp", "17179869184")
+		require.Equal(t, []float64{34359738368, 34359738368},
+			[]float64{rdb.HIncrByFloat(ctx, "smallhash", "tmp", 17179869184).Val(),
+				rdb.HIncrByFloat(ctx, "bighash", "tmp", 17179869184).Val()})
 	})
 
-	t.Run("HRange stop <= start", func(t *testing.T) {
-		require.NoError(t, rdb.Del(ctx, "hashkey").Err())
-		require.NoError(t, rdb.HMSet(ctx, "hashkey", kvArray).Err())
-		require.EqualValues(t, []interface{}{}, rdb.Do(ctx, "HRange", "hashkey", "key2", "key1", "limit", 100).Val())
-		require.EqualValues(t, []interface{}{}, rdb.Do(ctx, "HRange", "hashkey", "key1", "key1", "limit", 100).Val())
+	t.Run("HINCRBYFLOAT fails against hash value with spaces (left)", func(t *testing.T) {
+		rdb.HSet(ctx, "samllhash", "str", " 11")
+		rdb.HSet(ctx, "bighash", "str", " 11")
+		pattern := "ERR.*not.*float.*"
+		util.ErrorRegexp(t, rdb.HIncrByFloat(ctx, "samllhash", "str", 1).Err(), pattern)
+		util.ErrorRegexp(t, rdb.HIncrByFloat(ctx, "bighash", "str", 1).Err(), pattern)
 	})
 
-	t.Run("HRange limit", func(t *testing.T) {
-		require.NoError(t, rdb.Del(ctx, "hashkey").Err())
-		require.NoError(t, rdb.HMSet(ctx, "hashkey", kvArray).Err())
-		require.EqualValues(t, []interface{}{"a", "a", "b", "b"}, rdb.Do(ctx, "HRange", "hashkey", "a", "z", "limit", 2).Val())
-		require.EqualValues(t, []interface{}{"a", "a", "b", "b", "c", "c", "d", "d", "e", "e", "key1", "value1", "key10", "value10", "key2", "value2", "key3", "value3", "x", "x", "z", "z"}, rdb.Do(ctx, "HRange", "hashkey", "a", "zzz", "limit", 10000).Val())
+	t.Run("HINCRBYFLOAT fails against hash value with spaces (right)", func(t *testing.T) {
+		rdb.HSet(ctx, "samllhash", "str", "11 ")
+		rdb.HSet(ctx, "bighash", "str", "11 ")
+		pattern := "ERR.*not.*float.*"
+		util.ErrorRegexp(t, rdb.HIncrByFloat(ctx, "samllhash", "str", 1).Err(), pattern)
+		util.ErrorRegexp(t, rdb.HIncrByFloat(ctx, "bighash", "str", 1).Err(), pattern)
 	})
 
-	t.Run("HRange limit is negative", func(t *testing.T) {
-		require.NoError(t, rdb.Del(ctx, "hashkey").Err())
-		require.NoError(t, rdb.HMSet(ctx, "hashkey", kvArray).Err())
-		require.EqualValues(t, []interface{}{}, rdb.Do(ctx, "HRange", "hashkey", "a", "z", "limit", -100).Val())
-		require.EqualValues(t, []interface{}{}, rdb.Do(ctx, "HRange", "hashkey", "a", "z", "limit", 0).Val())
+	t.Run("HSTRLEN against the small hash", func(t *testing.T) {
+		var err error
+		for _, k := range getKeys(smallhash) {
+			hlen := rdb.Do(ctx, "hstrlen", "smallhash", k).Val().(int64)
+			if int64(len(smallhash[k])) != hlen {
+				err = fmt.Errorf("[string length %d] != [r hstrlen %d]", len(smallhash[k]), hlen)
+				break
+			}
+		}
+		require.NoError(t, err)
 	})
 
-	t.Run("HRange nonexistent key", func(t *testing.T) {
-		require.NoError(t, rdb.Del(ctx, "hashkey").Err())
-		require.EqualValues(t, []interface{}{}, rdb.Do(ctx, "HRange", "hashkey", "a", "z", "limit", 10000).Val())
-		require.EqualValues(t, []interface{}{}, rdb.Do(ctx, "HRange", "hashkey", "a", "z", "limit", 10000).Val())
+	t.Run("HSTRLEN against the big hash", func(t *testing.T) {
+		var err error
+		for _, k := range getKeys(bighash) {
+			hlen := rdb.Do(ctx, "hstrlen", "bighash", k).Val().(int64)
+			if int64(len(bighash[k])) != hlen {
+				err = fmt.Errorf("[string length %d] != [r hstrlen %d]", len(bighash[k]), hlen)
+				break
+			}
+		}
+		require.NoError(t, err)
 	})
 
-	t.Run("HRange limit typo", func(t *testing.T) {
-		require.NoError(t, rdb.Del(ctx, "hashkey").Err())
-		require.NoError(t, rdb.HMSet(ctx, "hashkey", kvArray).Err())
-		require.ErrorContains(t, rdb.Do(ctx, "HRange", "hashkey", "a", "z", "limitzz", 10000).Err(), "ERR syntax")
+	t.Run("HSTRLEN against non existing field", func(t *testing.T) {
+		var rv []int64
+		rv = append(rv, rdb.Do(ctx, "hstrlen", "smallhash", "__123123123__").Val().(int64))
+		rv = append(rv, rdb.Do(ctx, "hstrlen", "bighash", "__123123123__").Val().(int64))
+		require.Equal(t, []int64{0, 0}, rv)
 	})
 
-	t.Run("HRange wrong number of arguments", func(t *testing.T) {
-		require.NoError(t, rdb.Del(ctx, "hashkey").Err())
-		require.NoError(t, rdb.HMSet(ctx, "hashkey", kvArray).Err())
-		require.ErrorContains(t, rdb.Do(ctx, "HRange", "hashkey", "a", "z", "limit", 10000, "a").Err(), "wrong number of arguments")
-		require.ErrorContains(t, rdb.Do(ctx, "HRange", "hashkey", "a", "z", "limit").Err(), "wrong number of arguments")
-		require.ErrorContains(t, rdb.Do(ctx, "HRange", "hashkey", "a").Err(), "wrong number of arguments")
-		require.ErrorContains(t, rdb.Do(ctx, "HRange", "hashkey").Err(), "wrong number of arguments")
-		require.ErrorContains(t, rdb.Do(ctx, "HRange").Err(), "wrong number of arguments")
+	t.Run("HSTRLEN corner cases", func(t *testing.T) {
+		vals := []string{"-9223372036854775808", "9223372036854775807", "9223372036854775808", "", "0", "-1", "x"}
+		for _, v := range vals {
+			rdb.HMSet(ctx, "smallhash", "field", v)
+			rdb.HMSet(ctx, "bighash", "field", v)
+			len1 := int64(len(v))
+			len2 := rdb.Do(ctx, "hstrlen", "smallhash", "field").Val().(int64)
+			len3 := rdb.Do(ctx, "hstrlen", "bighash", "field").Val().(int64)
+			require.Equal(t, len1, len2)
+			require.Equal(t, len2, len3)
+		}
 	})
 
+	t.Run("Hash ziplist regression test for large keys", func(t *testing.T) {
+		rdb.HSet(ctx, "hash", strings.Repeat("k", 336), "a")
+		rdb.HSet(ctx, "hash", strings.Repeat("k", 336), "b")
+		require.Equal(t, "b", rdb.HGet(ctx, "hash", strings.Repeat("k", 336)).Val())
+	})
+
+	for _, size := range []int64{10, 512} {
+		t.Run(fmt.Sprintf("Hash fuzzing #1 - %d fields", size), func(t *testing.T) {
+			for times := 0; times < 10; times++ {
+				hash := make(map[string]string)
+				rdb.Del(ctx, "hash")
+
+				// Create
+				for j := 0; j < int(size); j++ {
+					field := util.RandomValue()
+					value := util.RandomValue()
+					rdb.HSet(ctx, "hash", field, value)
+					hash[field] = value
+				}
+
+				// Verify
+				for k, v := range hash {
+					require.Equal(t, v, rdb.HGet(ctx, "hash", k).Val())
+				}
+				require.Equal(t, int64(len(hash)), rdb.HLen(ctx, "hash").Val())
+			}
+		})
+
+		t.Run(fmt.Sprintf("Hash fuzzing #2 - %d fields", size), func(t *testing.T) {
+			for times := 0; times < 10; times++ {
+				hash := make(map[string]string)
+				rdb.Del(ctx, "hash")
+				var field string
+				var value string
+
+				// Create
+				for j := 0; j < int(size); j++ {
+					util.RandPath(
+						func() interface{} {
+							field = util.RandomValue()
+							value = util.RandomValue()
+							rdb.HSet(ctx, "hash", field, value)
+							hash[field] = value
+							return nil
+						},
+						func() interface{} {
+							field = strconv.Itoa(int(util.RandomSignedInt(512)))
+							value = strconv.Itoa(int(util.RandomSignedInt(512)))
+							rdb.HSet(ctx, "hash", field, value)
+							hash[field] = value
+							return nil
+						},
+						func() interface{} {
+							util.RandPath(
+								func() interface{} {
+									field = util.RandomValue()
+									return nil
+								},
+								func() interface{} {
+									field = strconv.Itoa(int(util.RandomSignedInt(512)))
+									return nil
+								},
+							)
+							rdb.HDel(ctx, "hash", field)
+							delete(hash, field)
+							return nil
+						},
+					)
+				}
+				// Verify
+				for k, v := range hash {
+					require.Equal(t, v, rdb.HGet(ctx, "hash", k).Val())
+				}
+				require.Equal(t, int64(len(hash)), rdb.HLen(ctx, "hash").Val())
+			}
+		})
+
+		kvArray := []string{"a", "a", "b", "b", "c", "c", "d", "d", "e", "e", "key1", "value1", "key2", "value2", "key3", "value3", "key10", "value10", "z", "z", "x", "x"}
+		t.Run("HRange normal situation ", func(t *testing.T) {
+			require.NoError(t, rdb.Del(ctx, "hashkey").Err())
+			require.NoError(t, rdb.HMSet(ctx, "hashkey", kvArray).Err())
+			require.EqualValues(t, []interface{}{"key1", "value1", "key10", "value10"}, rdb.Do(ctx, "HRange", "hashkey", "key1", "key2", "limit", 100).Val())
+			require.EqualValues(t, []interface{}{"key1", "value1", "key10", "value10", "key2", "value2"}, rdb.Do(ctx, "HRange", "hashkey", "key1", "key3", "limit", 100).Val())
+		})
+
+		t.Run("HRange stop <= start", func(t *testing.T) {
+			require.NoError(t, rdb.Del(ctx, "hashkey").Err())
+			require.NoError(t, rdb.HMSet(ctx, "hashkey", kvArray).Err())
+			require.EqualValues(t, []interface{}{}, rdb.Do(ctx, "HRange", "hashkey", "key2", "key1", "limit", 100).Val())
+			require.EqualValues(t, []interface{}{}, rdb.Do(ctx, "HRange", "hashkey", "key1", "key1", "limit", 100).Val())
+		})
+
+		t.Run("HRange limit", func(t *testing.T) {
+			require.NoError(t, rdb.Del(ctx, "hashkey").Err())
+			require.NoError(t, rdb.HMSet(ctx, "hashkey", kvArray).Err())
+			require.EqualValues(t, []interface{}{"a", "a", "b", "b"}, rdb.Do(ctx, "HRange", "hashkey", "a", "z", "limit", 2).Val())
+			require.EqualValues(t, []interface{}{"a", "a", "b", "b", "c", "c", "d", "d", "e", "e", "key1", "value1", "key10", "value10", "key2", "value2", "key3", "value3", "x", "x", "z", "z"}, rdb.Do(ctx, "HRange", "hashkey", "a", "zzz", "limit", 10000).Val())
+		})
+
+		t.Run("HRange limit is negative", func(t *testing.T) {
+			require.NoError(t, rdb.Del(ctx, "hashkey").Err())
+			require.NoError(t, rdb.HMSet(ctx, "hashkey", kvArray).Err())
+			require.EqualValues(t, []interface{}{}, rdb.Do(ctx, "HRange", "hashkey", "a", "z", "limit", -100).Val())
+			require.EqualValues(t, []interface{}{}, rdb.Do(ctx, "HRange", "hashkey", "a", "z", "limit", 0).Val())
+		})
+
+		t.Run("HRange nonexistent key", func(t *testing.T) {
+			require.NoError(t, rdb.Del(ctx, "hashkey").Err())
+			require.EqualValues(t, []interface{}{}, rdb.Do(ctx, "HRange", "hashkey", "a", "z", "limit", 10000).Val())
+			require.EqualValues(t, []interface{}{}, rdb.Do(ctx, "HRange", "hashkey", "a", "z", "limit", 10000).Val())
+		})
+
+		t.Run("HRange limit typo", func(t *testing.T) {
+			require.NoError(t, rdb.Del(ctx, "hashkey").Err())
+			require.NoError(t, rdb.HMSet(ctx, "hashkey", kvArray).Err())
+			require.ErrorContains(t, rdb.Do(ctx, "HRange", "hashkey", "a", "z", "limitzz", 10000).Err(), "ERR syntax")
+		})
+
+		t.Run("HRange wrong number of arguments", func(t *testing.T) {
+			require.NoError(t, rdb.Del(ctx, "hashkey").Err())
+			require.NoError(t, rdb.HMSet(ctx, "hashkey", kvArray).Err())
+			require.ErrorContains(t, rdb.Do(ctx, "HRange", "hashkey", "a", "z", "limit", 10000, "a").Err(), "wrong number of arguments")
+			require.ErrorContains(t, rdb.Do(ctx, "HRange", "hashkey", "a", "z", "limit").Err(), "wrong number of arguments")
+			require.ErrorContains(t, rdb.Do(ctx, "HRange", "hashkey", "a").Err(), "wrong number of arguments")
+			require.ErrorContains(t, rdb.Do(ctx, "HRange", "hashkey").Err(), "wrong number of arguments")
+			require.ErrorContains(t, rdb.Do(ctx, "HRange").Err(), "wrong number of arguments")
+		})
+	}
 }
diff --git a/tests/gocase/util/random.go b/tests/gocase/util/random.go
index c8b949b..bb114aa 100644
--- a/tests/gocase/util/random.go
+++ b/tests/gocase/util/random.go
@@ -36,7 +36,7 @@ func RandPathNoResult(funcs ...func()) {
 }
 
 // Random signed integer in (-max, max)
-func randomSignedInt(max int32) int64 {
+func RandomSignedInt(max int32) int64 {
 	return rand.Int63n(int64(max)*2-1) - int64(max) + 1
 }
 
@@ -78,7 +78,7 @@ func RandomValue() string {
 	return RandPath(
 		// Small enough to likely collide
 		func() string {
-			return fmt.Sprintf("%d", randomSignedInt(1000))
+			return fmt.Sprintf("%d", RandomSignedInt(1000))
 		},
 		// 32 bit compressible signed/unsigned
 		func() string {
diff --git a/tests/tcl/tests/test_helper.tcl b/tests/tcl/tests/test_helper.tcl
index d16a59c..0596bf7 100644
--- a/tests/tcl/tests/test_helper.tcl
+++ b/tests/tcl/tests/test_helper.tcl
@@ -37,7 +37,6 @@ set ::all_tests {
     unit/type/string
     unit/type/list
     unit/type/zset
-    unit/type/hash
     unit/type/stream
     unit/multi
     unit/expire
diff --git a/tests/tcl/tests/unit/type/hash.tcl b/tests/tcl/tests/unit/type/hash.tcl
deleted file mode 100644
index 0352eae..0000000
--- a/tests/tcl/tests/unit/type/hash.tcl
+++ /dev/null
@@ -1,528 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-
-# Copyright (c) 2006-2020, Salvatore Sanfilippo
-# See bundled license file licenses/LICENSE.redis for details.
-
-# This file is copied and modified from the Redis project,
-# which started out as: https://github.com/redis/redis/blob/dbcc0a8/tests/unit/type/hash.tcl
-
-start_server {tags {"hash"}} {
-    test {HSET/HLEN - Small hash creation} {
-        array set smallhash {}
-        for {set i 0} {$i < 8} {incr i} {
-            set key __avoid_collisions__[randstring 0 8 alpha]
-            set val __avoid_collisions__[randstring 0 8 alpha]
-            if {[info exists smallhash($key)]} {
-                incr i -1
-                continue
-            }
-            r hset smallhash $key $val
-            set smallhash($key) $val
-        }
-        list [r hlen smallhash]
-    } {8}
-
-    test {HSET/HLEN - Big hash creation} {
-        array set bighash {}
-        for {set i 0} {$i < 1024} {incr i} {
-            set key __avoid_collisions__[randstring 0 8 alpha]
-            set val __avoid_collisions__[randstring 0 8 alpha]
-            if {[info exists bighash($key)]} {
-                incr i -1
-                continue
-            }
-            r hset bighash $key $val
-            set bighash($key) $val
-        }
-        list [r hlen bighash]
-    } {1024}
-
-    test {HSET wrong number of args} {
-        catch {r hset hmsetmulti key1 val1 key2} err
-        format $err
-    } {*wrong number*}
-
-    test {HSET supports multiple fields} {
-        assert_equal "2" [r hset hmsetmulti key1 val1 key2 val2]
-        assert_equal "0" [r hset hmsetmulti key1 val1 key2 val2]
-        assert_equal "1" [r hset hmsetmulti key1 val1 key3 val3]
-    }
-
-    test {HGET against the small hash} {
-        set err {}
-        foreach k [array names smallhash *] {
-            if {$smallhash($k) ne [r hget smallhash $k]} {
-                set err "$smallhash($k) != [r hget smallhash $k]"
-                break
-            }
-        }
-        set _ $err
-    } {}
-
-    test {HGET against the big hash} {
-        set err {}
-        foreach k [array names bighash *] {
-            if {$bighash($k) ne [r hget bighash $k]} {
-                set err "$bighash($k) != [r hget bighash $k]"
-                break
-            }
-        }
-        set _ $err
-    } {}
-
-    test {HGET against non existing key} {
-        set rv {}
-        lappend rv [r hget smallhash __123123123__]
-        lappend rv [r hget bighash __123123123__]
-        set _ $rv
-    } {{} {}}
-
-    test {HSET in update and insert mode} {
-        set rv {}
-        set k [lindex [array names smallhash *] 0]
-        lappend rv [r hset smallhash $k newval1]
-        set smallhash($k) newval1
-        lappend rv [r hget smallhash $k]
-        lappend rv [r hset smallhash __foobar123__ newval]
-        set k [lindex [array names bighash *] 0]
-        lappend rv [r hset bighash $k newval2]
-        set bighash($k) newval2
-        lappend rv [r hget bighash $k]
-        lappend rv [r hset bighash __foobar123__ newval]
-        lappend rv [r hdel smallhash __foobar123__]
-        lappend rv [r hdel bighash __foobar123__]
-        set _ $rv
-    } {0 newval1 1 0 newval2 1 1 1}
-
-    test {HSETNX target key missing - small hash} {
-        r hsetnx smallhash __123123123__ foo
-        r hget smallhash __123123123__
-    } {foo}
-
-    test {HSETNX target key exists - small hash} {
-        r hsetnx smallhash __123123123__ bar
-        set result [r hget smallhash __123123123__]
-        r hdel smallhash __123123123__
-        set _ $result
-    } {foo}
-
-    test {HSETNX target key missing - big hash} {
-        r hsetnx bighash __123123123__ foo
-        r hget bighash __123123123__
-    } {foo}
-
-    test {HSETNX target key exists - big hash} {
-        r hsetnx bighash __123123123__ bar
-        set result [r hget bighash __123123123__]
-        r hdel bighash __123123123__
-        set _ $result
-    } {foo}
-
-    test {HMSET wrong number of args} {
-        catch {r hmset smallhash key1 val1 key2} err
-        format $err
-    } {*wrong number*}
-
-    test {HMSET - small hash} {
-        set args {}
-        foreach {k v} [array get smallhash] {
-            set newval [randstring 0 8 alpha]
-            set smallhash($k) $newval
-            lappend args $k $newval
-        }
-        r hmset smallhash {*}$args
-    } {OK}
-
-    test {HMSET - big hash} {
-        set args {}
-        foreach {k v} [array get bighash] {
-            set newval [randstring 0 8 alpha]
-            set bighash($k) $newval
-            lappend args $k $newval
-        }
-        r hmset bighash {*}$args
-    } {OK}
-
-    test {HMGET against non existing key and fields} {
-        set rv {}
-        lappend rv [r hmget doesntexist __123123123__ __456456456__]
-        lappend rv [r hmget smallhash __123123123__ __456456456__]
-        lappend rv [r hmget bighash __123123123__ __456456456__]
-        set _ $rv
-    } {{{} {}} {{} {}} {{} {}}}
-
-    test {HMGET against wrong type} {
-        r set wrongtype somevalue
-        assert_error "*wrong*" {r hmget wrongtype field1 field2}
-    }
-
-    test {HMGET - small hash} {
-        set keys {}
-        set vals {}
-        foreach {k v} [array get smallhash] {
-            lappend keys $k
-            lappend vals $v
-        }
-        set err {}
-        set result [r hmget smallhash {*}$keys]
-        if {$vals ne $result} {
-            set err "$vals != $result"
-            break
-        }
-        set _ $err
-    } {}
-
-    test {HMGET - big hash} {
-        set keys {}
-        set vals {}
-        foreach {k v} [array get bighash] {
-            lappend keys $k
-            lappend vals $v
-        }
-        set err {}
-        set result [r hmget bighash {*}$keys]
-        if {$vals ne $result} {
-            set err "$vals != $result"
-            break
-        }
-        set _ $err
-    } {}
-
-    test {HKEYS - small hash} {
-        lsort [r hkeys smallhash]
-    } [lsort [array names smallhash *]]
-
-    test {HKEYS - big hash} {
-        lsort [r hkeys bighash]
-    } [lsort [array names bighash *]]
-
-    test {HVALS - small hash} {
-        set vals {}
-        foreach {k v} [array get smallhash] {
-            lappend vals $v
-        }
-        set _ [lsort $vals]
-    } [lsort [r hvals smallhash]]
-
-    test {HVALS - big hash} {
-        set vals {}
-        foreach {k v} [array get bighash] {
-            lappend vals $v
-        }
-        set _ [lsort $vals]
-    } [lsort [r hvals bighash]]
-
-    test {HGETALL - small hash} {
-        lsort [r hgetall smallhash]
-    } [lsort [array get smallhash]]
-
-    test {HGETALL - big hash} {
-        lsort [r hgetall bighash]
-    } [lsort [array get bighash]]
-
-    test {HDEL and return value} {
-        set rv {}
-        lappend rv [r hdel smallhash nokey]
-        lappend rv [r hdel bighash nokey]
-        set k [lindex [array names smallhash *] 0]
-        lappend rv [r hdel smallhash $k]
-        lappend rv [r hdel smallhash $k]
-        lappend rv [r hget smallhash $k]
-        unset smallhash($k)
-        set k [lindex [array names bighash *] 0]
-        lappend rv [r hdel bighash $k]
-        lappend rv [r hdel bighash $k]
-        lappend rv [r hget bighash $k]
-        unset bighash($k)
-        set _ $rv
-    } {0 0 1 0 {} 1 0 {}}
-
-    test {HDEL - more than a single value} {
-        set rv {}
-        r del myhash
-        r hmset myhash a 1 b 2 c 3
-        assert_equal 0 [r hdel myhash x y]
-        assert_equal 2 [r hdel myhash a c f]
-        r hgetall myhash
-    } {b 2}
-
-    test {HDEL - hash becomes empty before deleting all specified fields} {
-        r del myhash
-        r hmset myhash a 1 b 2 c 3
-        assert_equal 3 [r hdel myhash a b c d e]
-        assert_equal 0 [r exists myhash]
-    }
-
-    test {HEXISTS} {
-        set rv {}
-        set k [lindex [array names smallhash *] 0]
-        lappend rv [r hexists smallhash $k]
-        lappend rv [r hexists smallhash nokey]
-        set k [lindex [array names bighash *] 0]
-        lappend rv [r hexists bighash $k]
-        lappend rv [r hexists bighash nokey]
-    } {1 0 1 0}
-
-    test {HINCRBY against non existing database key} {
-        r del htest
-        list [r hincrby htest foo 2]
-    } {2}
-
-    test {HINCRBY against non existing hash key} {
-        set rv {}
-        r hdel smallhash tmp
-        r hdel bighash tmp
-        lappend rv [r hincrby smallhash tmp 2]
-        lappend rv [r hget smallhash tmp]
-        lappend rv [r hincrby bighash tmp 2]
-        lappend rv [r hget bighash tmp]
-    } {2 2 2 2}
-
-    test {HINCRBY against hash key created by hincrby itself} {
-        set rv {}
-        lappend rv [r hincrby smallhash tmp 3]
-        lappend rv [r hget smallhash tmp]
-        lappend rv [r hincrby bighash tmp 3]
-        lappend rv [r hget bighash tmp]
-    } {5 5 5 5}
-
-    test {HINCRBY against hash key originally set with HSET} {
-        r hset smallhash tmp 100
-        r hset bighash tmp 100
-        list [r hincrby smallhash tmp 2] [r hincrby bighash tmp 2]
-    } {102 102}
-
-    test {HINCRBY over 32bit value} {
-        r hset smallhash tmp 17179869184
-        r hset bighash tmp 17179869184
-        list [r hincrby smallhash tmp 1] [r hincrby bighash tmp 1]
-    } {17179869185 17179869185}
-
-    test {HINCRBY over 32bit value with over 32bit increment} {
-        r hset smallhash tmp 17179869184
-        r hset bighash tmp 17179869184
-        list [r hincrby smallhash tmp 17179869184] [r hincrby bighash tmp 17179869184]
-    } {34359738368 34359738368}
-
-    test {HINCRBY fails against hash value with spaces (left)} {
-        r hset smallhash str " 11"
-        r hset bighash str " 11"
-        catch {r hincrby smallhash str 1} smallerr
-        catch {r hincrby smallhash str 1} bigerr
-        set rv {}
-        lappend rv [string match "ERR*not an integer*" $smallerr]
-        lappend rv [string match "ERR*not an integer*" $bigerr]
-    } {1 1}
-
-    test {HINCRBY fails against hash value with spaces (right)} {
-        r hset smallhash str "11 "
-        r hset bighash str "11 "
-        catch {r hincrby smallhash str 1} smallerr
-        catch {r hincrby smallhash str 1} bigerr
-        set rv {}
-        lappend rv [string match "ERR*non-integer*" $smallerr]
-        lappend rv [string match "ERR*non-integer*" $bigerr]
-    } {1 1}
-
-    test {HINCRBY can detect overflows} {
-        set e {}
-        r hset hash n -9223372036854775484
-        assert {[r hincrby hash n -1] == -9223372036854775485}
-        catch {r hincrby hash n -10000} e
-        set e
-    } {*overflow*}
-
-    test {HINCRBYFLOAT against non existing database key} {
-        r del htest
-        list [r hincrbyfloat htest foo 2.5]
-    } {2.5}
-
-    test {HINCRBYFLOAT against non existing hash key} {
-        set rv {}
-        r hdel smallhash tmp
-        r hdel bighash tmp
-        lappend rv [roundFloat [r hincrbyfloat smallhash tmp 2.5]]
-        lappend rv [roundFloat [r hget smallhash tmp]]
-        lappend rv [roundFloat [r hincrbyfloat bighash tmp 2.5]]
-        lappend rv [roundFloat [r hget bighash tmp]]
-    } {2.5 2.5 2.5 2.5}
-
-    test {HINCRBYFLOAT against hash key created by hincrby itself} {
-        set rv {}
-        lappend rv [roundFloat [r hincrbyfloat smallhash tmp 3.5]]
-        lappend rv [roundFloat [r hget smallhash tmp]]
-        lappend rv [roundFloat [r hincrbyfloat bighash tmp 3.5]]
-        lappend rv [roundFloat [r hget bighash tmp]]
-    } {6 6 6 6}
-
-    test {HINCRBYFLOAT against hash key originally set with HSET} {
-        r hset smallhash tmp 100
-        r hset bighash tmp 100
-        list [roundFloat [r hincrbyfloat smallhash tmp 2.5]] \
-             [roundFloat [r hincrbyfloat bighash tmp 2.5]]
-    } {102.5 102.5}
-
-    test {HINCRBYFLOAT over 32bit value} {
-        r hset smallhash tmp 17179869184
-        r hset bighash tmp 17179869184
-        list [r hincrbyfloat smallhash tmp 1] \
-             [r hincrbyfloat bighash tmp 1]
-    } {17179869185 17179869185}
-
-    test {HINCRBYFLOAT over 32bit value with over 32bit increment} {
-        r hset smallhash tmp 17179869184
-        r hset bighash tmp 17179869184
-        list [r hincrbyfloat smallhash tmp 17179869184] \
-             [r hincrbyfloat bighash tmp 17179869184]
-    } {34359738368 34359738368}
-
-    test {HINCRBYFLOAT fails against hash value with spaces (left)} {
-        r hset smallhash str " 11"
-        r hset bighash str " 11"
-        catch {r hincrbyfloat smallhash str 1} smallerr
-        catch {r hincrbyfloat smallhash str 1} bigerr
-        set rv {}
-        lappend rv [string match "ERR*not*float*" $smallerr]
-        lappend rv [string match "ERR*not*float*" $bigerr]
-    } {1 1}
-
-    test {HINCRBYFLOAT fails against hash value with spaces (right)} {
-        r hset smallhash str "11 "
-        r hset bighash str "11 "
-        catch {r hincrbyfloat smallhash str 1} smallerr
-        catch {r hincrbyfloat smallhash str 1} bigerr
-        set rv {}
-        lappend rv [string match "ERR*not*float*" $smallerr]
-        lappend rv [string match "ERR*not*float*" $bigerr]
-    } {1 1}
-
-    test {HSTRLEN against the small hash} {
-        set err {}
-        foreach k [array names smallhash *] {
-            if {[string length $smallhash($k)] ne [r hstrlen smallhash $k]} {
-                set err "[string length $smallhash($k)] != [r hstrlen smallhash $k]"
-                break
-            }
-        }
-        set _ $err
-    } {}
-
-    test {HSTRLEN against the big hash} {
-        set err {}
-        foreach k [array names bighash *] {
-            if {[string length $bighash($k)] ne [r hstrlen bighash $k]} {
-                set err "[string length $bighash($k)] != [r hstrlen bighash $k]"
-                puts "HSTRLEN and logical length mismatch:"
-                puts "key: $k"
-                puts "Logical content: $bighash($k)"
-                puts "Server  content: [r hget bighash $k]"
-            }
-        }
-        set _ $err
-    } {}
-
-    test {HSTRLEN against non existing field} {
-        set rv {}
-        lappend rv [r hstrlen smallhash __123123123__]
-        lappend rv [r hstrlen bighash __123123123__]
-        set _ $rv
-    } {0 0}
-
-    test {HSTRLEN corner cases} {
-        set vals {
-            -9223372036854775808 9223372036854775807 9223372036854775808
-            {} 0 -1 x
-        }
-        foreach v $vals {
-            r hmset smallhash field $v
-            r hmset bighash field $v
-            set len1 [string length $v]
-            set len2 [r hstrlen smallhash field]
-            set len3 [r hstrlen bighash field]
-            assert {$len1 == $len2}
-            assert {$len2 == $len3}
-        }
-    }
-
-    test {Hash ziplist regression test for large keys} {
-        r hset hash kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk a
-        r hset hash kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk b
-        r hget hash kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
-    } {b}
-
-    foreach size {10 512} {
-        test "Hash fuzzing #1 - $size fields" {
-            for {set times 0} {$times < 10} {incr times} {
-                catch {unset hash}
-                array set hash {}
-                r del hash
-
-                # Create
-                for {set j 0} {$j < $size} {incr j} {
-                    set field [randomValue]
-                    set value [randomValue]
-                    r hset hash $field $value
-                    set hash($field) $value
-                }
-
-                # Verify
-                foreach {k v} [array get hash] {
-                    assert_equal $v [r hget hash $k]
-                }
-                assert_equal [array size hash] [r hlen hash]
-            }
-        }
-
-        test "Hash fuzzing #2 - $size fields" {
-            for {set times 0} {$times < 10} {incr times} {
-                catch {unset hash}
-                array set hash {}
-                r del hash
-
-                # Create
-                for {set j 0} {$j < $size} {incr j} {
-                    randpath {
-                        set field [randomValue]
-                        set value [randomValue]
-                        r hset hash $field $value
-                        set hash($field) $value
-                    } {
-                        set field [randomSignedInt 512]
-                        set value [randomSignedInt 512]
-                        r hset hash $field $value
-                        set hash($field) $value
-                    } {
-                        randpath {
-                            set field [randomValue]
-                        } {
-                            set field [randomSignedInt 512]
-                        }
-                        r hdel hash $field
-                        unset -nocomplain hash($field)
-                    }
-                }
-
-                # Verify
-                foreach {k v} [array get hash] {
-                    assert_equal $v [r hget hash $k]
-                }
-                assert_equal [array size hash] [r hlen hash]
-            }
-        }
-    }
-}