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 5a269c0f Move TCL test unit/type/list to Go case (#1009)
5a269c0f is described below

commit 5a269c0f71c128a50b5688c341a175a1487e01d8
Author: IoCing <[email protected]>
AuthorDate: Wed Oct 19 00:28:45 2022 +0800

    Move TCL test unit/type/list to Go case (#1009)
    
    Co-authored-by: tison <[email protected]>
    Co-authored-by: Ruixiang Tan <[email protected]>
---
 .github/workflows/kvrocks.yaml            |   1 -
 tests/gocase/unit/type/list/list_test.go  | 626 ++++++++++++++++++++++
 tests/gocase/util/tcp_client.go           |  15 +
 tests/tcl/tests/test_helper.tcl           |   1 -
 tests/tcl/tests/unit/type/list-common.tcl |  28 -
 tests/tcl/tests/unit/type/list.tcl        | 838 ------------------------------
 6 files changed, 641 insertions(+), 868 deletions(-)

diff --git a/.github/workflows/kvrocks.yaml b/.github/workflows/kvrocks.yaml
index 5088b5e8..75965cfe 100644
--- a/.github/workflows/kvrocks.yaml
+++ b/.github/workflows/kvrocks.yaml
@@ -226,7 +226,6 @@ jobs:
       - name: Run Redis Tcl Test
         run: |
           export ${{ matrix.runtime_env_vars }}
-          ./x.py test tcl build --cli-path $HOME/local/bin/redis-cli 
--dont-clean
           if [[ -n "${{ matrix.with_openssl }}" ]] && [[ "${{ matrix.os }}" == 
ubuntu* ]]; then
             git clone https://github.com/jsha/minica
             cd minica && go build && cd ..
diff --git a/tests/gocase/unit/type/list/list_test.go 
b/tests/gocase/unit/type/list/list_test.go
index 579bfabe..1473daee 100644
--- a/tests/gocase/unit/type/list/list_test.go
+++ b/tests/gocase/unit/type/list/list_test.go
@@ -237,3 +237,629 @@ func TestZipList(t *testing.T) {
                }
        })
 }
+
+func TestList(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()) }()
+       rd := srv.NewTCPClient()
+       defer func() { require.NoError(t, rd.Close()) }()
+
+       t.Run("LPUSH, RPUSH, LLENGTH, LINDEX, LPOP - ziplist", func(t 
*testing.T) {
+               // first lpush then rpush
+               require.EqualValues(t, 1, rdb.LPush(ctx, "myziplist1", 
"aa").Val())
+               require.EqualValues(t, 2, rdb.RPush(ctx, "myziplist1", 
"bb").Val())
+               require.EqualValues(t, 3, rdb.RPush(ctx, "myziplist1", 
"cc").Val())
+               require.EqualValues(t, 3, rdb.LLen(ctx, "myziplist1").Val())
+               require.Equal(t, "aa", rdb.LIndex(ctx, "myziplist1", 0).Val())
+               require.Equal(t, "bb", rdb.LIndex(ctx, "myziplist1", 1).Val())
+               require.Equal(t, "cc", rdb.LIndex(ctx, "myziplist1", 2).Val())
+               require.Equal(t, "", rdb.LIndex(ctx, "myziplist1", 3).Val())
+               require.Equal(t, "cc", rdb.RPop(ctx, "myziplist1").Val())
+               require.Equal(t, "aa", rdb.LPop(ctx, "myziplist1").Val())
+
+               // first rpush then lpush
+               require.EqualValues(t, 1, rdb.RPush(ctx, "myziplist2", 
"a").Val())
+               require.EqualValues(t, 2, rdb.LPush(ctx, "myziplist2", 
"b").Val())
+               require.EqualValues(t, 3, rdb.LPush(ctx, "myziplist2", 
"c").Val())
+               require.EqualValues(t, 3, rdb.LLen(ctx, "myziplist2").Val())
+               require.Equal(t, "c", rdb.LIndex(ctx, "myziplist2", 0).Val())
+               require.Equal(t, "b", rdb.LIndex(ctx, "myziplist2", 1).Val())
+               require.Equal(t, "a", rdb.LIndex(ctx, "myziplist2", 2).Val())
+               require.Equal(t, "", rdb.LIndex(ctx, "myziplist2", 3).Val())
+               require.Equal(t, "a", rdb.RPop(ctx, "myziplist2").Val())
+               require.Equal(t, "c", rdb.LPop(ctx, "myziplist2").Val())
+       })
+
+       t.Run("LPUSH, RPUSH, LLENGTH, LINDEX, LPOP - regular list", func(t 
*testing.T) {
+               // first lpush then rpush
+               require.EqualValues(t, 1, rdb.LPush(ctx, "mylist1", 
largeValue["linkedList"]).Val())
+               require.EqualValues(t, 2, rdb.RPush(ctx, "mylist1", "b").Val())
+               require.EqualValues(t, 3, rdb.RPush(ctx, "mylist1", "c").Val())
+               require.EqualValues(t, 3, rdb.LLen(ctx, "mylist1").Val())
+               require.Equal(t, largeValue["linkedList"], rdb.LIndex(ctx, 
"mylist1", 0).Val())
+               require.Equal(t, "b", rdb.LIndex(ctx, "mylist1", 1).Val())
+               require.Equal(t, "c", rdb.LIndex(ctx, "mylist1", 2).Val())
+               require.Equal(t, "", rdb.LIndex(ctx, "mylist1", 3).Val())
+               require.Equal(t, "c", rdb.RPop(ctx, "mylist1").Val())
+               require.Equal(t, largeValue["linkedList"], rdb.LPop(ctx, 
"mylist1").Val())
+
+               // first rpush then lpush
+               require.EqualValues(t, 1, rdb.RPush(ctx, "mylist2", 
largeValue["linkedList"]).Val())
+               require.EqualValues(t, 2, rdb.LPush(ctx, "mylist2", "b").Val())
+               require.EqualValues(t, 3, rdb.LPush(ctx, "mylist2", "c").Val())
+               require.EqualValues(t, 3, rdb.LLen(ctx, "mylist2").Val())
+               require.Equal(t, "c", rdb.LIndex(ctx, "mylist2", 0).Val())
+               require.Equal(t, "b", rdb.LIndex(ctx, "mylist2", 1).Val())
+               require.Equal(t, largeValue["linkedList"], rdb.LIndex(ctx, 
"mylist2", 2).Val())
+               require.Equal(t, "", rdb.LIndex(ctx, "mylist2", 3).Val())
+               require.Equal(t, largeValue["linkedList"], rdb.RPop(ctx, 
"mylist2").Val())
+               require.Equal(t, "c", rdb.LPop(ctx, "mylist2").Val())
+       })
+
+       t.Run("R/LPOP against empty list", func(t *testing.T) {
+               require.Equal(t, "", rdb.LPop(ctx, "non-existing-list").Val())
+       })
+
+       t.Run("Variadic RPUSH/LPUSH", func(t *testing.T) {
+               require.NoError(t, rdb.Del(ctx, "mylist").Err())
+               require.EqualValues(t, 4, rdb.LPush(ctx, "mylist", "a", "b", 
"c", "d").Val())
+               require.EqualValues(t, 8, rdb.RPush(ctx, "mylist", "1", "2", 
"3", "4").Val())
+               require.Equal(t, []string{"d", "c", "b", "a", "1", "2", "3", 
"4"}, rdb.LRange(ctx, "mylist", 0, -1).Val())
+       })
+
+       t.Run("DEL a list", func(t *testing.T) {
+               require.EqualValues(t, 1, rdb.Del(ctx, "mylist2").Val())
+               require.EqualValues(t, 0, rdb.Exists(ctx, "mylist2").Val())
+               require.EqualValues(t, 0, rdb.LLen(ctx, "mylist2").Val())
+       })
+
+       createList := func(key string, entries ...interface{}) {
+               require.NoError(t, rdb.Del(ctx, key).Err())
+               for _, entry := range entries {
+                       require.NoError(t, rdb.RPush(ctx, key, entry).Err())
+               }
+       }
+
+       for listType, large := range largeValue {
+               t.Run(fmt.Sprintf("BLPOP, BRPOP: single existing list - %s", 
listType), func(t *testing.T) {
+                       createList("blist", []string{"a", "b", large, "c", "d"})
+                       require.NoError(t, rd.WriteArgs("blpop", "blist", "1"))
+                       rd.MustReadStrings(t, []string{"blist", "a"})
+                       require.NoError(t, rd.WriteArgs("brpop", "blist", "1"))
+                       rd.MustReadStrings(t, []string{"blist", "d"})
+                       require.NoError(t, rd.WriteArgs("blpop", "blist", "1"))
+                       rd.MustReadStrings(t, []string{"blist", "b"})
+                       require.NoError(t, rd.WriteArgs("brpop", "blist", "1"))
+                       rd.MustReadStrings(t, []string{"blist", "c"})
+               })
+
+               t.Run(fmt.Sprintf("BLPOP, BRPOP: multiple existing lists - %s", 
listType), func(t *testing.T) {
+                       createList("blist1", []string{"a", large, "c"})
+                       createList("blist2", []string{"d", large, "f"})
+                       require.NoError(t, rd.WriteArgs("blpop", "blist1", 
"blist2", "1"))
+                       rd.MustReadStrings(t, []string{"blist1", "a"})
+                       require.NoError(t, rd.WriteArgs("brpop", "blist1", 
"blist2", "1"))
+                       rd.MustReadStrings(t, []string{"blist1", "c"})
+                       require.EqualValues(t, 1, rdb.LLen(ctx, "blist1").Val())
+                       require.EqualValues(t, 3, rdb.LLen(ctx, "blist2").Val())
+                       require.NoError(t, rd.WriteArgs("blpop", "blist2", 
"blist2", "1"))
+                       rd.MustReadStrings(t, []string{"blist2", "d"})
+                       require.NoError(t, rd.WriteArgs("brpop", "blist2", 
"blist2", "1"))
+                       rd.MustReadStrings(t, []string{"blist2", "f"})
+                       require.EqualValues(t, 1, rdb.LLen(ctx, "blist1").Val())
+                       require.EqualValues(t, 1, rdb.LLen(ctx, "blist2").Val())
+               })
+
+               t.Run(fmt.Sprintf("BLPOP, BRPOP: second list has an entry - 
%s", listType), func(t *testing.T) {
+                       require.NoError(t, rdb.Del(ctx, "blist1").Err())
+                       createList("blist2", []string{"d", large, "f"})
+                       require.NoError(t, rd.WriteArgs("blpop", "blist1", 
"blist2", "1"))
+                       rd.MustReadStrings(t, []string{"blist2", "d"})
+                       require.NoError(t, rd.WriteArgs("brpop", "blist1", 
"blist2", "1"))
+                       rd.MustReadStrings(t, []string{"blist2", "f"})
+                       require.EqualValues(t, 0, rdb.LLen(ctx, "blist1").Val())
+                       require.EqualValues(t, 1, rdb.LLen(ctx, "blist2").Val())
+               })
+       }
+
+       t.Run("BLPOP with same key multiple times should work (redis issue 
#801)", func(t *testing.T) {
+               require.NoError(t, rdb.Del(ctx, "list1", "list2").Err())
+               require.NoError(t, rd.WriteArgs("blpop", "list1", "list2", 
"list2", "list1", "0"))
+               require.NoError(t, rdb.LPush(ctx, "list1", "a").Err())
+               rd.MustReadStrings(t, []string{"list1", "a"})
+               require.NoError(t, rd.WriteArgs("blpop", "list1", "list2", 
"list2", "list1", "0"))
+               require.NoError(t, rdb.LPush(ctx, "list2", "b").Err())
+               rd.MustReadStrings(t, []string{"list2", "b"})
+               require.NoError(t, rdb.LPush(ctx, "list1", "a").Err())
+               require.NoError(t, rdb.LPush(ctx, "list2", "b").Err())
+               require.NoError(t, rd.WriteArgs("blpop", "list1", "list2", 
"list2", "list1", "0"))
+               rd.MustReadStrings(t, []string{"list1", "a"})
+               require.NoError(t, rd.WriteArgs("blpop", "list1", "list2", 
"list2", "list1", "0"))
+               rd.MustReadStrings(t, []string{"list2", "b"})
+       })
+
+       t.Run("BLPOP with variadic LPUSH", func(t *testing.T) {
+               require.NoError(t, rdb.Del(ctx, "blist", "target").Err())
+               time.Sleep(time.Millisecond * 100)
+               require.NoError(t, rd.WriteArgs("blpop", "blist", "0"))
+               time.Sleep(time.Millisecond * 100)
+               require.EqualValues(t, 2, rdb.LPush(ctx, "blist", "foo", 
"bar").Val())
+               time.Sleep(time.Millisecond * 100)
+               rd.MustReadStrings(t, []string{"blist", "bar"})
+               require.Equal(t, "foo", rdb.LRange(ctx, "blist", 0, 
-1).Val()[0])
+       })
+
+       for _, popType := range []string{"blpop", "brpop"} {
+               t.Run(fmt.Sprintf("%s: with single empty list argument", 
popType), func(t *testing.T) {
+                       require.NoError(t, rdb.Del(ctx, "blist1").Err())
+                       require.NoError(t, rd.WriteArgs(popType, "blist1", "1"))
+                       require.NoError(t, rdb.RPush(ctx, "blist1", 
"foo").Err())
+                       rd.MustReadStrings(t, []string{"blist1", "foo"})
+                       require.EqualValues(t, 0, rdb.Exists(ctx, 
"blist1").Val())
+               })
+
+               t.Run(fmt.Sprintf("%s: with negative timeout", popType), func(t 
*testing.T) {
+                       require.NoError(t, rd.WriteArgs(popType, "blist1", 
"-1"))
+                       rd.MustMatch(t, ".*negative.*")
+               })
+
+               t.Run(fmt.Sprintf("%s: with zero timeout should block 
indefinitely", popType), func(t *testing.T) {
+                       // To test this, use a timeout of 0 and wait a second.
+                       // The blocking pop should still be waiting for a push.
+                       require.NoError(t, rd.WriteArgs(popType, "blist1", "0"))
+                       time.Sleep(time.Millisecond * 1000)
+                       require.NoError(t, rdb.RPush(ctx, "blist1", 
"foo").Err())
+                       rd.MustReadStrings(t, []string{"blist1", "foo"})
+               })
+
+               t.Run(fmt.Sprintf("%s: second argument is not a list", 
popType), func(t *testing.T) {
+                       require.NoError(t, rdb.Del(ctx, "blist1", 
"blist2").Err())
+                       require.NoError(t, rdb.Set(ctx, "blist2", "nolist", 
0).Err())
+                       require.NoError(t, rd.WriteArgs(popType, "blist1", 
"blist2", "1"))
+                       rd.MustMatch(t, ".*WRONGTYPE.*")
+               })
+
+               t.Run(fmt.Sprintf("%s: timeout", popType), func(t *testing.T) {
+                       require.NoError(t, rdb.Del(ctx, "blist1", 
"blist2").Err())
+                       require.NoError(t, rd.WriteArgs(popType, "blist1", 
"blist2", "1"))
+                       rd.MustMatch(t, "")
+               })
+
+               t.Run(fmt.Sprintf("%s: arguments are empty", popType), func(t 
*testing.T) {
+                       require.NoError(t, rdb.Del(ctx, "blist1", 
"blist2").Err())
+                       require.NoError(t, rd.WriteArgs(popType, "blist1", 
"blist2", "1"))
+                       require.NoError(t, rdb.RPush(ctx, "blist1", 
"foo").Err())
+                       rd.MustReadStrings(t, []string{"blist1", "foo"})
+                       require.EqualValues(t, 0, rdb.Exists(ctx, 
"blist1").Val())
+                       require.EqualValues(t, 0, rdb.Exists(ctx, 
"blist2").Val())
+                       require.NoError(t, rd.WriteArgs(popType, "blist1", 
"blist2", "1"))
+                       require.NoError(t, rdb.RPush(ctx, "blist2", 
"foo").Err())
+                       rd.MustReadStrings(t, []string{"blist2", "foo"})
+                       require.EqualValues(t, 0, rdb.Exists(ctx, 
"blist1").Val())
+                       require.EqualValues(t, 0, rdb.Exists(ctx, 
"blist2").Val())
+               })
+       }
+
+       t.Run("LPUSHX, RPUSHX - generic", func(t *testing.T) {
+               require.NoError(t, rdb.Del(ctx, "xlist").Err())
+               require.EqualValues(t, 0, rdb.LPushX(ctx, "xlist", "a").Val())
+               require.EqualValues(t, 0, rdb.LLen(ctx, "xlist").Val())
+               require.EqualValues(t, 0, rdb.RPushX(ctx, "xlist", "a").Val())
+               require.EqualValues(t, 0, rdb.LLen(ctx, "xlist").Val())
+       })
+
+       for listType, large := range largeValue {
+               t.Run(fmt.Sprintf("LPUSHX, RPUSHX - %s", listType), func(t 
*testing.T) {
+                       createList("xlist", []string{large, "c"})
+                       require.EqualValues(t, 3, rdb.RPushX(ctx, "xlist", 
"d").Val())
+                       require.EqualValues(t, 4, rdb.LPushX(ctx, "xlist", 
"a").Val())
+                       require.EqualValues(t, 6, rdb.RPushX(ctx, "xlist", 
"42", "x").Val())
+                       require.EqualValues(t, 9, rdb.LPushX(ctx, "xlist", 
"y3", "y2", "y1").Val())
+                       require.Equal(t, []string{"y1", "y2", "y3", "a", large, 
"c", "d", "42", "x"}, rdb.LRange(ctx, "xlist", 0, -1).Val())
+               })
+
+               t.Run(fmt.Sprintf("LINSERT - %s", listType), func(t *testing.T) 
{
+                       createList("xlist", []string{"a", large, "c", "d"})
+                       require.EqualValues(t, 5, rdb.LInsert(ctx, "xlist", 
"before", "c", "zz").Val())
+                       require.Equal(t, []string{"a", large, "zz", "c", "d"}, 
rdb.LRange(ctx, "xlist", 0, 10).Val())
+                       require.EqualValues(t, 6, rdb.LInsert(ctx, "xlist", 
"after", "c", "yy").Val())
+                       require.Equal(t, []string{"a", large, "zz", "c", "yy", 
"d"}, rdb.LRange(ctx, "xlist", 0, 10).Val())
+                       require.EqualValues(t, 7, rdb.LInsert(ctx, "xlist", 
"after", "d", "dd").Val())
+                       require.EqualValues(t, -1, rdb.LInsert(ctx, "xlist", 
"after", "bad", "ddd").Val())
+                       require.Equal(t, []string{"a", large, "zz", "c", "yy", 
"d", "dd"}, rdb.LRange(ctx, "xlist", 0, 10).Val())
+                       require.EqualValues(t, 8, rdb.LInsert(ctx, "xlist", 
"before", "a", "aa").Val())
+                       require.EqualValues(t, -1, rdb.LInsert(ctx, "xlist", 
"before", "bad", "aaa").Val())
+                       require.Equal(t, []string{"aa", "a", large, "zz", "c", 
"yy", "d", "dd"}, rdb.LRange(ctx, "xlist", 0, 10).Val())
+
+                       // check inserting integer encoded value
+                       require.EqualValues(t, 9, rdb.LInsert(ctx, "xlist", 
"before", "aa", "42").Val())
+                       require.Equal(t, "42", rdb.LRange(ctx, "xlist", 0, 
0).Val()[0])
+               })
+       }
+
+       t.Run("LINSERT raise error on bad syntax", func(t *testing.T) {
+               util.ErrorRegexp(t, rdb.LInsert(ctx, "xlist", "aft3r", "aa", 
"42").Err(), ".*syntax.*error.*")
+       })
+
+       listType := "quicklist"
+       for _, num := range []int{250, 500} {
+               checkNumberedListConsistency := func(key string) {
+                       l := rdb.LLen(ctx, key).Val()
+                       for i := 0; i < int(l); i++ {
+                               require.Equal(t, strconv.Itoa(i), 
rdb.LIndex(ctx, key, int64(i)).Val())
+                               require.Equal(t, strconv.Itoa(int(l)-i-1), 
rdb.LIndex(ctx, key, int64(int(l)-i-1)).Val())
+                       }
+               }
+
+               checkRandomAccessConsistency := func(key string) {
+                       l := rdb.LLen(ctx, key).Val()
+                       for i := 0; i < int(l); i++ {
+                               k := rand.Intn(int(l))
+                               require.Equal(t, strconv.Itoa(k), 
rdb.LIndex(ctx, key, int64(k)).Val())
+                               require.Equal(t, strconv.Itoa(int(l)-k-1), 
rdb.LIndex(ctx, key, int64(int(l)-k-1)).Val())
+                       }
+               }
+
+               t.Run(fmt.Sprintf("LINDEX consistency test - %s", listType), 
func(t *testing.T) {
+                       require.NoError(t, rdb.Del(ctx, "mylist").Err())
+                       for i := 0; i < num; i++ {
+                               require.NoError(t, rdb.RPush(ctx, "mylist", 
strconv.Itoa(i)).Err())
+                       }
+                       checkNumberedListConsistency("mylist")
+               })
+
+               t.Run(fmt.Sprintf("LINDEX random access - %s", listType), 
func(t *testing.T) {
+                       checkRandomAccessConsistency("mylist")
+               })
+
+               t.Run(fmt.Sprintf("Check if list is still ok after a DEBUG 
RELOAD - %s", listType), func(t *testing.T) {
+                       checkNumberedListConsistency("mylist")
+                       checkRandomAccessConsistency("mylist")
+               })
+       }
+       t.Run("LLEN against non-list value error", func(t *testing.T) {
+               require.NoError(t, rdb.Del(ctx, "mylist").Err())
+               require.NoError(t, rdb.Set(ctx, "mylist", "foobar", 0).Err())
+               require.ErrorContains(t, rdb.LLen(ctx, "mylist").Err(), 
"WRONGTYPE")
+       })
+
+       t.Run("LLEN against non existing key", func(t *testing.T) {
+               require.EqualValues(t, 0, rdb.LLen(ctx, "not-a-key").Val())
+       })
+
+       t.Run("LINDEX against non-list value error", func(t *testing.T) {
+               require.ErrorContains(t, rdb.LIndex(ctx, "mylist", 0).Err(), 
"WRONGTYPE")
+       })
+
+       t.Run("LINDEX against non existing key", func(t *testing.T) {
+               require.Equal(t, "", rdb.LIndex(ctx, "not-a-key", 10).Val())
+       })
+
+       t.Run("LPUSH against non-list value error", func(t *testing.T) {
+               require.ErrorContains(t, rdb.LPush(ctx, "mylist", 0).Err(), 
"WRONGTYPE")
+       })
+
+       t.Run("RPUSH against non-list value error", func(t *testing.T) {
+               require.ErrorContains(t, rdb.RPush(ctx, "mylist", 0).Err(), 
"WRONGTYPE")
+       })
+
+       for listType, large := range largeValue {
+               t.Run(fmt.Sprintf("RPOPLPUSH base case - %s", listType), func(t 
*testing.T) {
+                       require.NoError(t, rdb.Del(ctx, "mylist1", 
"mylist2").Err())
+                       createList("mylist1", []string{"a", large, "c", "d"})
+                       require.Equal(t, "d", rdb.RPopLPush(ctx, "mylist1", 
"mylist2").Val())
+                       require.Equal(t, "c", rdb.RPopLPush(ctx, "mylist1", 
"mylist2").Val())
+                       require.Equal(t, []string{"a", large}, rdb.LRange(ctx, 
"mylist1", 0, -1).Val())
+                       require.Equal(t, []string{"c", "d"}, rdb.LRange(ctx, 
"mylist2", 0, -1).Val())
+               })
+
+               t.Run(fmt.Sprintf("RPOPLPUSH with the same list as src and dst 
- %s", listType), func(t *testing.T) {
+                       createList("mylist", []string{"a", large, "c"})
+                       require.Equal(t, []string{"a", large, "c"}, 
rdb.LRange(ctx, "mylist", 0, -1).Val())
+                       require.Equal(t, "c", rdb.RPopLPush(ctx, "mylist", 
"mylist").Val())
+                       require.Equal(t, []string{"c", "a", large}, 
rdb.LRange(ctx, "mylist", 0, -1).Val())
+               })
+
+               for otherListType, otherLarge := range largeValue {
+                       t.Run(fmt.Sprintf("RPOPLPUSH with %s source and 
existing target %s", listType, otherListType), func(t *testing.T) {
+                               createList("srclist", []string{"a", "b", "c", 
large})
+                               createList("dstlist", []string{otherLarge})
+                               require.Equal(t, large, rdb.RPopLPush(ctx, 
"srclist", "dstlist").Val())
+                               require.Equal(t, "c", rdb.RPopLPush(ctx, 
"srclist", "dstlist").Val())
+                               require.Equal(t, []string{"a", "b"}, 
rdb.LRange(ctx, "srclist", 0, -1).Val())
+                               require.Equal(t, []string{"c", large, 
otherLarge}, rdb.LRange(ctx, "dstlist", 0, -1).Val())
+                       })
+               }
+       }
+
+       t.Run("RPOPLPUSH against non existing key", func(t *testing.T) {
+               require.NoError(t, rdb.Del(ctx, "srclist", "dstlist").Err())
+               require.Equal(t, "", rdb.RPopLPush(ctx, "srclist", 
"dstlist").Val())
+               require.EqualValues(t, 0, rdb.Exists(ctx, "srclist").Val())
+               require.EqualValues(t, 0, rdb.Exists(ctx, "dstlist").Val())
+       })
+
+       t.Run("RPOPLPUSH against non list src key", func(t *testing.T) {
+               require.NoError(t, rdb.Del(ctx, "srclist", "dstlist").Err())
+               require.NoError(t, rdb.Set(ctx, "srclist", "x", 0).Err())
+               require.ErrorContains(t, rdb.RPopLPush(ctx, "srclist", 
"dstlist").Err(), "WRONGTYPE")
+               require.Equal(t, "string", rdb.Type(ctx, "srclist").Val())
+               require.EqualValues(t, 0, rdb.Exists(ctx, "newlist").Val())
+       })
+
+       t.Run("RPOPLPUSH against non list dst key", func(t *testing.T) {
+               createList("srclist", []string{"a", "b", "c", "d"})
+               require.NoError(t, rdb.Set(ctx, "dstlist", "x", 0).Err())
+               require.ErrorContains(t, rdb.RPopLPush(ctx, "srclist", 
"dstlist").Err(), "WRONGTYPE")
+               require.Equal(t, "string", rdb.Type(ctx, "dstlist").Val())
+               require.Equal(t, []string{"a", "b", "c", "d"}, rdb.LRange(ctx, 
"srclist", 0, -1).Val())
+       })
+
+       t.Run("RPOPLPUSH against non existing src key", func(t *testing.T) {
+               require.NoError(t, rdb.Del(ctx, "srclist", "dstlist").Err())
+               require.Equal(t, "", rdb.RPopLPush(ctx, "srclist", 
"dstlist").Val())
+       })
+
+       for listType, large := range largeValue {
+               t.Run(fmt.Sprintf("Basic LPOP/RPOP - %s", listType), func(t 
*testing.T) {
+                       createList("mylist", []string{large, "1", "2"})
+
+                       require.Equal(t, large, rdb.LPop(ctx, "mylist").Val())
+                       require.Equal(t, "2", rdb.RPop(ctx, "mylist").Val())
+                       require.Equal(t, "1", rdb.LPop(ctx, "mylist").Val())
+                       require.EqualValues(t, 0, rdb.LLen(ctx, "mylist").Val())
+
+                       // pop on empty list
+                       require.Equal(t, "", rdb.LPop(ctx, "mylist").Val())
+                       require.Equal(t, "", rdb.LPop(ctx, "mylist").Val())
+               })
+       }
+
+       t.Run("LPOP/RPOP against non list value", func(t *testing.T) {
+               require.NoError(t, rdb.Set(ctx, "notalist", "foo", 0).Err())
+               require.ErrorContains(t, rdb.LPop(ctx, "notalist").Err(), 
"WRONGTYPE")
+               require.ErrorContains(t, rdb.RPop(ctx, "notalist").Err(), 
"WRONGTYPE")
+       })
+
+       t.Run("LPOP/RPOP with wrong number of arguments", func(t *testing.T) {
+               require.ErrorContains(t, rdb.Do(ctx, "lpop", "key", "1", 
"1").Err(), "wrong number of arguments")
+               require.ErrorContains(t, rdb.Do(ctx, "lpop", "key", "2", 
"2").Err(), "wrong number of arguments")
+       })
+
+       t.Run("RPOP/LPOP with the optional count argument", func(t *testing.T) {
+               require.EqualValues(t, 7, rdb.LPush(ctx, "listcount", "aa", 
"bb", "cc", "dd", "ee", "ff", "gg").Val())
+               require.Equal(t, []string{"gg"}, rdb.LPopCount(ctx, 
"listcount", 1).Val())
+               require.Equal(t, []string{"ff", "ee"}, rdb.LPopCount(ctx, 
"listcount", 2).Val())
+               require.Equal(t, []string{"aa", "bb"}, rdb.RPopCount(ctx, 
"listcount", 2).Val())
+               require.Equal(t, []string{"cc"}, rdb.RPopCount(ctx, 
"listcount", 1).Val())
+               require.Equal(t, []string{"dd"}, rdb.LPopCount(ctx, 
"listcount", 123).Val())
+               util.ErrorRegexp(t, rdb.LPopCount(ctx, "forbatqaz", 
-123).Err(), ".*ERR.*range.*")
+       })
+
+       t.Run("LPOP/RPOP with the count 0 returns an empty array", func(t 
*testing.T) {
+               require.NoError(t, rdb.LPush(ctx, "listcount", "zero").Err())
+               require.Equal(t, []string{}, rdb.LPopCount(ctx, "listcount", 
0).Val())
+               require.Equal(t, []string{}, rdb.RPopCount(ctx, "listcount", 
0).Val())
+       })
+
+       t.Run("LPOP/RPOP against non existing key", func(t *testing.T) {
+               require.NoError(t, rdb.Del(ctx, "non_existing_key").Err())
+               require.EqualError(t, rdb.LPop(ctx, "non_existing_key").Err(), 
redis.Nil.Error())
+               require.EqualError(t, rdb.RPop(ctx, "non_existing_key").Err(), 
redis.Nil.Error())
+       })
+
+       t.Run("LPOP/RPOP with <count> against non existing key", func(t 
*testing.T) {
+               require.NoError(t, rdb.Del(ctx, "non_existing_key").Err())
+               require.EqualError(t, rdb.LPopCount(ctx, "non_existing_key", 
0).Err(), redis.Nil.Error())
+               require.EqualError(t, rdb.LPopCount(ctx, "non_existing_key", 
1).Err(), redis.Nil.Error())
+               require.EqualError(t, rdb.RPopCount(ctx, "non_existing_key", 
0).Err(), redis.Nil.Error())
+               require.EqualError(t, rdb.RPopCount(ctx, "non_existing_key", 
1).Err(), redis.Nil.Error())
+       })
+
+       listType = "quicklist"
+       for _, num := range []int{250, 500} {
+               t.Run(fmt.Sprintf("Mass RPOP/LPOP - %s", listType), func(t 
*testing.T) {
+                       require.NoError(t, rdb.Del(ctx, "mylist").Err())
+                       sum1 := 0
+                       for i := 0; i < num; i++ {
+                               require.NoError(t, rdb.LPush(ctx, "mylist", 
strconv.Itoa(i)).Err())
+                               sum1 += i
+                       }
+                       sum2 := 0
+                       for i := 0; i < num/2; i++ {
+                               if v1, err := strconv.Atoi(rdb.LPop(ctx, 
"mylist").Val()); err == nil {
+                                       sum2 += v1
+                               }
+                               if v2, err := strconv.Atoi(rdb.RPop(ctx, 
"mylist").Val()); err == nil {
+                                       sum2 += v2
+                               }
+                       }
+                       require.Equal(t, sum1, sum2)
+               })
+       }
+
+       for listType, large := range largeValue {
+               t.Run(fmt.Sprintf("LRANGE basics - %s", listType), func(t 
*testing.T) {
+                       createList("mylist", []string{large, "1", "2", "3", 
"4", "5", "6", "7", "8", "9"})
+                       require.Equal(t, []string{"1", "2", "3", "4", "5", "6", 
"7", "8"}, rdb.LRange(ctx, "mylist", 1, -2).Val())
+                       require.Equal(t, []string{"7", "8", "9"}, 
rdb.LRange(ctx, "mylist", -3, -1).Val())
+                       require.Equal(t, []string{"4"}, rdb.LRange(ctx, 
"mylist", 4, 4).Val())
+               })
+
+               t.Run(fmt.Sprintf("LRANGE inverted indexes - %s", listType), 
func(t *testing.T) {
+                       createList("mylist", []string{large, "1", "2", "3", 
"4", "5", "6", "7", "8", "9"})
+                       require.Equal(t, []string{}, rdb.LRange(ctx, "mylist", 
6, 2).Val())
+               })
+
+               t.Run(fmt.Sprintf("LRANGE out of range indexes including the 
full list - $type - %s", listType), func(t *testing.T) {
+                       createList("mylist", []string{large, "1", "2", "3"})
+                       require.Equal(t, []string{large, "1", "2", "3"}, 
rdb.LRange(ctx, "mylist", -1000, 1000).Val())
+               })
+
+               t.Run(fmt.Sprintf("LRANGE out of range negative end index - 
%s", listType), func(t *testing.T) {
+                       createList("mylist", []string{large, "1", "2", "3"})
+                       require.Equal(t, []string{large}, rdb.LRange(ctx, 
"mylist", 0, -4).Val())
+                       require.Equal(t, []string{}, rdb.LRange(ctx, "mylist", 
0, -5).Val())
+               })
+       }
+
+       t.Run("LRANGE against non existing key", func(t *testing.T) {
+               require.Equal(t, []string{}, rdb.LRange(ctx, "nosuchkey", 0, 
1).Val())
+       })
+
+       for listType, large := range largeValue {
+               trimList := func(listType string, min, max int64) []string {
+                       require.NoError(t, rdb.Del(ctx, "mylist").Err())
+                       createList("mylist", []string{"1", "2", "3", "4", 
large})
+                       require.NoError(t, rdb.LTrim(ctx, "mylist", min, 
max).Err())
+                       return rdb.LRange(ctx, "mylist", 0, -1).Val()
+               }
+
+               t.Run(fmt.Sprintf("LTRIM basics - %s", listType), func(t 
*testing.T) {
+                       require.Equal(t, []string{"1"}, trimList(listType, 0, 
0))
+                       require.Equal(t, []string{"1", "2"}, trimList(listType, 
0, 1))
+                       require.Equal(t, []string{"1", "2", "3"}, 
trimList(listType, 0, 2))
+                       require.Equal(t, []string{"2", "3"}, trimList(listType, 
1, 2))
+                       require.Equal(t, []string{"2", "3", "4", large}, 
trimList(listType, 1, -1))
+                       require.Equal(t, []string{"2", "3", "4"}, 
trimList(listType, 1, -2))
+                       require.Equal(t, []string{"4", large}, 
trimList(listType, -2, -1))
+                       require.Equal(t, []string{large}, trimList(listType, 
-1, -1))
+                       require.Equal(t, []string{"1", "2", "3", "4", large}, 
trimList(listType, -5, -1))
+                       require.Equal(t, []string{"1", "2", "3", "4", large}, 
trimList(listType, -10, 10))
+                       require.Equal(t, []string{"1", "2", "3", "4", large}, 
trimList(listType, 0, 5))
+                       require.Equal(t, []string{"1", "2", "3", "4", large}, 
trimList(listType, 0, 10))
+               })
+
+               t.Run(fmt.Sprintf("LTRIM out of range negative end index - %s", 
listType), func(t *testing.T) {
+                       require.Equal(t, []string{"1"}, trimList(listType, 0, 
-5))
+                       require.Equal(t, []string{}, trimList(listType, 0, -6))
+               })
+
+               t.Run(fmt.Sprintf("LTRIM lrem elements after ltrim list - %s", 
listType), func(t *testing.T) {
+                       createList("myotherlist", []string{"0", "1", "2", "3", 
"4", "3", "6", "7", "3", "9"})
+                       require.Equal(t, "OK", rdb.LTrim(ctx, "myotherlist", 2, 
-3).Val())
+                       require.Equal(t, []string{"2", "3", "4", "3", "6", 
"7"}, rdb.LRange(ctx, "myotherlist", 0, -1).Val())
+                       require.EqualValues(t, 2, rdb.LRem(ctx, "myotherlist", 
4, "3").Val())
+                       require.Equal(t, []string{"2", "4", "6", "7"}, 
rdb.LRange(ctx, "myotherlist", 0, -1).Val())
+               })
+
+               t.Run(fmt.Sprintf("LTRIM linsert elements after ltrim list - 
%s", listType), func(t *testing.T) {
+                       createList("myotherlist1", []string{"0", "1", "2", "3", 
"4", "3", "6", "7", "3", "9"})
+                       require.Equal(t, "OK", rdb.LTrim(ctx, "myotherlist1", 
2, -3).Val())
+                       require.Equal(t, []string{"2", "3", "4", "3", "6", 
"7"}, rdb.LRange(ctx, "myotherlist1", 0, -1).Val())
+                       require.EqualValues(t, -1, rdb.LInsert(ctx, 
"myotherlist1", "before", "9", "0").Val())
+                       require.EqualValues(t, 7, rdb.LInsert(ctx, 
"myotherlist1", "before", "4", "0").Val())
+                       require.Equal(t, []string{"2", "3", "0", "4", "3", "6", 
"7"}, rdb.LRange(ctx, "myotherlist1", 0, -1).Val())
+               })
+       }
+
+       for listType, large := range largeValue {
+               t.Run(fmt.Sprintf("LSET - %s", listType), func(t *testing.T) {
+                       createList("mylist", []string{"99", "98", large, "96", 
"95"})
+                       require.NoError(t, rdb.LSet(ctx, "mylist", 1, 
"foo").Err())
+                       require.NoError(t, rdb.LSet(ctx, "mylist", -1, 
"bar").Err())
+                       require.Equal(t, []string{"99", "foo", large, "96", 
"bar"}, rdb.LRange(ctx, "mylist", 0, -1).Val())
+               })
+
+               t.Run(fmt.Sprintf("LSET out of range index - %s", listType), 
func(t *testing.T) {
+                       util.ErrorRegexp(t, rdb.LSet(ctx, "mylist", 10, 
"foo").Err(), "ERR.*range.*")
+               })
+       }
+
+       t.Run("LSET against non existing key", func(t *testing.T) {
+               util.ErrorRegexp(t, rdb.LSet(ctx, "nosuchkey", 10, 
"foo").Err(), "ERR.*NotFound.*")
+       })
+
+       t.Run("LSET against non list value", func(t *testing.T) {
+               require.NoError(t, rdb.Set(ctx, "nolist", "foobar", 0).Err())
+               require.ErrorContains(t, rdb.LSet(ctx, "nolist", 0, 
"foo").Err(), "WRONGTYPE")
+       })
+
+       for listType, e := range largeValue {
+               t.Run(fmt.Sprintf("LREM remove all the occurrences - %s", 
listType), func(t *testing.T) {
+                       createList("mylist", []string{e, "foo", "bar", 
"foobar", "foobared", "zap", "bar", "test", "foo"})
+                       require.EqualValues(t, 2, rdb.LRem(ctx, "mylist", 0, 
"bar").Val())
+                       require.Equal(t, []string{e, "foo", "foobar", 
"foobared", "zap", "test", "foo"}, rdb.LRange(ctx, "mylist", 0, -1).Val())
+               })
+
+               t.Run(fmt.Sprintf("LREM remove the first occurrence - %s", 
listType), func(t *testing.T) {
+                       require.EqualValues(t, 1, rdb.LRem(ctx, "mylist", 1, 
"foo").Val())
+                       require.Equal(t, []string{e, "foobar", "foobared", 
"zap", "test", "foo"}, rdb.LRange(ctx, "mylist", 0, -1).Val())
+               })
+
+               t.Run(fmt.Sprintf("LREM remove non existing element - %s", 
listType), func(t *testing.T) {
+                       require.EqualValues(t, 0, rdb.LRem(ctx, "mylist", 1, 
"nosuchelement").Val())
+                       require.Equal(t, []string{e, "foobar", "foobared", 
"zap", "test", "foo"}, rdb.LRange(ctx, "mylist", 0, -1).Val())
+               })
+
+               t.Run(fmt.Sprintf("LREM starting from tail with negative count 
- %s", listType), func(t *testing.T) {
+                       createList("mylist", []string{e, "foo", "bar", 
"foobar", "foobared", "zap", "bar", "test", "foo", "foo"})
+                       require.EqualValues(t, 1, rdb.LRem(ctx, "mylist", -1, 
"bar").Val())
+                       require.Equal(t, []string{e, "foo", "bar", "foobar", 
"foobared", "zap", "test", "foo", "foo"}, rdb.LRange(ctx, "mylist", 0, 
-1).Val())
+               })
+
+               t.Run(fmt.Sprintf("LREM starting from tail with negative count 
(2) - %s", listType), func(t *testing.T) {
+                       require.EqualValues(t, 2, rdb.LRem(ctx, "mylist", -2, 
"foo").Val())
+                       require.Equal(t, []string{e, "foo", "bar", "foobar", 
"foobared", "zap", "test"}, rdb.LRange(ctx, "mylist", 0, -1).Val())
+               })
+
+               t.Run(fmt.Sprintf("LREM deleting objects that may be int 
encoded - %s", listType), func(t *testing.T) {
+                       createList("myotherlist", e, 1, 2, 3)
+                       require.EqualValues(t, 1, rdb.LRem(ctx, "myotherlist", 
1, 2).Val())
+                       require.EqualValues(t, 3, rdb.LLen(ctx, 
"myotherlist").Val())
+               })
+
+               t.Run(fmt.Sprintf("LREM remove elements in repeating list - 
%s", listType), func(t *testing.T) {
+                       createList("myotherlist", e, "a", "b", "c", "d", "e", 
"f", "a", "f", "a", "f")
+                       require.EqualValues(t, 1, rdb.LRem(ctx, "myotherlist", 
1, "f").Val())
+                       require.Equal(t, []string{e, "a", "b", "c", "d", "e", 
"a", "f", "a", "f"}, rdb.LRange(ctx, "myotherlist", 0, -1).Val())
+                       require.EqualValues(t, 2, rdb.LRem(ctx, "myotherlist", 
0, "f").Val())
+                       require.Equal(t, []string{e, "a", "b", "c", "d", "e", 
"a", "a"}, rdb.LRange(ctx, "myotherlist", 0, -1).Val())
+               })
+       }
+
+       t.Run("Test LMOVE on different keys", func(t *testing.T) {
+               require.NoError(t, rdb.RPush(ctx, "list1{t}", "1").Err())
+               require.NoError(t, rdb.RPush(ctx, "list1{t}", "2").Err())
+               require.NoError(t, rdb.RPush(ctx, "list1{t}", "3").Err())
+               require.NoError(t, rdb.RPush(ctx, "list1{t}", "4").Err())
+               require.NoError(t, rdb.RPush(ctx, "list1{t}", "5").Err())
+               require.NoError(t, rdb.LMove(ctx, "list1{t}", "list2{t}", 
"RIGHT", "LEFT").Err())
+               require.NoError(t, rdb.LMove(ctx, "list1{t}", "list2{t}", 
"LEFT", "RIGHT").Err())
+               require.EqualValues(t, 3, rdb.LLen(ctx, "list1{t}").Val())
+               require.EqualValues(t, 2, rdb.LLen(ctx, "list2{t}").Val())
+               require.Equal(t, []string{"2", "3", "4"}, rdb.LRange(ctx, 
"list1{t}", 0, -1).Val())
+               require.Equal(t, []string{"5", "1"}, rdb.LRange(ctx, 
"list2{t}", 0, -1).Val())
+       })
+
+       for _, from := range []string{"LEFT", "RIGHT"} {
+               for _, to := range []string{"LEFT", "RIGHT"} {
+                       t.Run(fmt.Sprintf("LMOVE %s %s on the list node", from, 
to), func(t *testing.T) {
+                               require.NoError(t, rdb.Del(ctx, 
"target_key{t}").Err())
+                               require.NoError(t, rdb.RPush(ctx, 
"target_key{t}", 1).Err())
+                               createList("list{t}", []string{"a", "b", "c", 
"d"})
+                               require.NoError(t, rd.WriteArgs("lmove", 
"list{t}", "target_key{t}", from, to))
+                               r, err1 := rd.ReadLine()
+                               require.Equal(t, "$1", r)
+                               require.NoError(t, err1)
+                               elem, err2 := rd.ReadLine()
+                               require.NoError(t, err2)
+                               if from == "RIGHT" {
+                                       require.Equal(t, elem, "d")
+                                       require.Equal(t, []string{"a", "b", 
"c"}, rdb.LRange(ctx, "list{t}", 0, -1).Val())
+                               } else {
+                                       require.Equal(t, elem, "a")
+                                       require.Equal(t, []string{"b", "c", 
"d"}, rdb.LRange(ctx, "list{t}", 0, -1).Val())
+                               }
+                               if to == "RIGHT" {
+                                       require.Equal(t, elem, rdb.RPop(ctx, 
"target_key{t}").Val())
+                               } else {
+                                       require.Equal(t, elem, rdb.LPop(ctx, 
"target_key{t}").Val())
+                               }
+                       })
+               }
+       }
+}
diff --git a/tests/gocase/util/tcp_client.go b/tests/gocase/util/tcp_client.go
index 0e8f7663..b364aef5 100644
--- a/tests/gocase/util/tcp_client.go
+++ b/tests/gocase/util/tcp_client.go
@@ -24,6 +24,7 @@ import (
        "errors"
        "fmt"
        "net"
+       "strconv"
        "strings"
        "testing"
 
@@ -62,6 +63,20 @@ func (c *TCPClient) MustRead(t testing.TB, s string) {
        require.Equal(t, s, r)
 }
 
+func (c *TCPClient) MustReadStrings(t testing.TB, s []string) {
+       r, err := c.ReadLine()
+       require.NoError(t, err)
+       require.EqualValues(t, '*', r[0])
+       n, err := strconv.Atoi(r[1:])
+       require.NoError(t, err)
+       require.Equal(t, n, len(s))
+       for i := 0; i < n; i++ {
+               _, err := c.ReadLine()
+               require.NoError(t, err)
+               c.MustRead(t, s[i])
+       }
+}
+
 func (c *TCPClient) MustMatch(t testing.TB, rx string) {
        r, err := c.ReadLine()
        require.NoError(t, err)
diff --git a/tests/tcl/tests/test_helper.tcl b/tests/tcl/tests/test_helper.tcl
index 2d99606e..72ca6412 100644
--- a/tests/tcl/tests/test_helper.tcl
+++ b/tests/tcl/tests/test_helper.tcl
@@ -33,7 +33,6 @@ source tests/support/test.tcl
 source tests/support/util.tcl
 
 set ::all_tests {
-    unit/type/list
 }
 
 # Index to the next test to run in the ::all_tests list.
diff --git a/tests/tcl/tests/unit/type/list-common.tcl 
b/tests/tcl/tests/unit/type/list-common.tcl
deleted file mode 100644
index c012ddd5..00000000
--- a/tests/tcl/tests/unit/type/list-common.tcl
+++ /dev/null
@@ -1,28 +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/list-common.tcl
-
-# We need a value larger than list-max-ziplist-value to make sure
-# the list has the right encoding when it is swapped in again.
-array set largevalue {}
-set largevalue(ziplist) "hello"
-set largevalue(linkedlist) [string repeat "hello" 4]
diff --git a/tests/tcl/tests/unit/type/list.tcl 
b/tests/tcl/tests/unit/type/list.tcl
deleted file mode 100644
index a8b78392..00000000
--- a/tests/tcl/tests/unit/type/list.tcl
+++ /dev/null
@@ -1,838 +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/list.tcl
-
-start_server {
-    tags {"list"}
-} {
-    source "tests/unit/type/list-common.tcl"
-
-    test {LPUSH, RPUSH, LLENGTH, LINDEX, LPOP - ziplist} {
-        # first lpush then rpush
-        assert_equal 1 [r lpush myziplist1 aa]
-        assert_equal 2 [r rpush myziplist1 bb]
-        assert_equal 3 [r rpush myziplist1 cc]
-        assert_equal 3 [r llen myziplist1]
-        assert_equal aa [r lindex myziplist1 0]
-        assert_equal bb [r lindex myziplist1 1]
-        assert_equal cc [r lindex myziplist1 2]
-        assert_equal {} [r lindex myziplist2 3]
-        assert_equal cc [r rpop myziplist1]
-        assert_equal aa [r lpop myziplist1]
-        #assert_encoding quicklist myziplist1
-
-        # first rpush then lpush
-        assert_equal 1 [r rpush myziplist2 a]
-        assert_equal 2 [r lpush myziplist2 b]
-        assert_equal 3 [r lpush myziplist2 c]
-        assert_equal 3 [r llen myziplist2]
-        assert_equal c [r lindex myziplist2 0]
-        assert_equal b [r lindex myziplist2 1]
-        assert_equal a [r lindex myziplist2 2]
-        assert_equal {} [r lindex myziplist2 3]
-        assert_equal a [r rpop myziplist2]
-        assert_equal c [r lpop myziplist2]
-        #assert_encoding quicklist myziplist2
-    }
-
-    test {LPUSH, RPUSH, LLENGTH, LINDEX, LPOP - regular list} {
-        # first lpush then rpush
-        assert_equal 1 [r lpush mylist1 $largevalue(linkedlist)]
-        #assert_encoding quicklist mylist1
-        assert_equal 2 [r rpush mylist1 b]
-        assert_equal 3 [r rpush mylist1 c]
-        assert_equal 3 [r llen mylist1]
-        assert_equal $largevalue(linkedlist) [r lindex mylist1 0]
-        assert_equal b [r lindex mylist1 1]
-        assert_equal c [r lindex mylist1 2]
-        assert_equal {} [r lindex mylist1 3]
-        assert_equal c [r rpop mylist1]
-        assert_equal $largevalue(linkedlist) [r lpop mylist1]
-
-        # first rpush then lpush
-        assert_equal 1 [r rpush mylist2 $largevalue(linkedlist)]
-        #assert_encoding quicklist mylist2
-        assert_equal 2 [r lpush mylist2 b]
-        assert_equal 3 [r lpush mylist2 c]
-        assert_equal 3 [r llen mylist2]
-        assert_equal c [r lindex mylist2 0]
-        assert_equal b [r lindex mylist2 1]
-        assert_equal $largevalue(linkedlist) [r lindex mylist2 2]
-        assert_equal {} [r lindex mylist2 3]
-        assert_equal $largevalue(linkedlist) [r rpop mylist2]
-        assert_equal c [r lpop mylist2]
-    }
-
-    test {R/LPOP against empty list} {
-        r lpop non-existing-list
-    } {}
-
-    test {Variadic RPUSH/LPUSH} {
-        r del mylist
-        assert_equal 4 [r lpush mylist a b c d]
-        assert_equal 8 [r rpush mylist 0 1 2 3]
-        assert_equal {d c b a 0 1 2 3} [r lrange mylist 0 -1]
-    }
-
-    test {DEL a list} {
-        assert_equal 1 [r del mylist2]
-        assert_equal 0 [r exists mylist2]
-        assert_equal 0 [r llen mylist2]
-    }
-
-    proc create_list {key entries} {
-        r del $key
-        foreach entry $entries { r rpush $key $entry }
-        #assert_encoding quicklist $key
-    }
-
-    foreach {type large} [array get largevalue] {
-        test "BLPOP, BRPOP: single existing list - $type" {
-            set rd [redis_deferring_client]
-            create_list blist "a b $large c d"
-
-            $rd blpop blist 1
-            assert_equal {blist a} [$rd read]
-            $rd brpop blist 1
-            assert_equal {blist d} [$rd read]
-
-            $rd blpop blist 1
-            assert_equal {blist b} [$rd read]
-            $rd brpop blist 1
-            assert_equal {blist c} [$rd read]
-        }
-
-        test "BLPOP, BRPOP: multiple existing lists - $type" {
-            set rd [redis_deferring_client]
-            create_list blist1 "a $large c"
-            create_list blist2 "d $large f"
-
-            $rd blpop blist1 blist2 1
-            assert_equal {blist1 a} [$rd read]
-            $rd brpop blist1 blist2 1
-            assert_equal {blist1 c} [$rd read]
-            assert_equal 1 [r llen blist1]
-            assert_equal 3 [r llen blist2]
-
-            $rd blpop blist2 blist1 1
-            assert_equal {blist2 d} [$rd read]
-            $rd brpop blist2 blist1 1
-            assert_equal {blist2 f} [$rd read]
-            assert_equal 1 [r llen blist1]
-            assert_equal 1 [r llen blist2]
-        }
-
-        test "BLPOP, BRPOP: second list has an entry - $type" {
-            set rd [redis_deferring_client]
-            r del blist1
-            create_list blist2 "d $large f"
-
-            $rd blpop blist1 blist2 1
-            assert_equal {blist2 d} [$rd read]
-            $rd brpop blist1 blist2 1
-            assert_equal {blist2 f} [$rd read]
-            assert_equal 0 [r llen blist1]
-            assert_equal 1 [r llen blist2]
-        }
-
-        # test "BRPOPLPUSH - $type" {
-        #     r del target
-
-        #     set rd [redis_deferring_client]
-        #     create_list blist "a b $large c d"
-
-        #     $rd brpoplpush blist target 1
-        #     assert_equal d [$rd read]
-
-        #     assert_equal d [r rpop target]
-        #     assert_equal "a b $large c" [r lrange blist 0 -1]
-        # }
-    }
-
-    test "BLPOP with same key multiple times should work (issue #801)" {
-        set rd [redis_deferring_client]
-        r del list1 list2
-
-        # Data arriving after the BLPOP.
-        $rd blpop list1 list2 list2 list1 0
-        r lpush list1 a
-        assert_equal [$rd read] {list1 a}
-        $rd blpop list1 list2 list2 list1 0
-        r lpush list2 b
-        assert_equal [$rd read] {list2 b}
-
-        # Data already there.
-        r lpush list1 a
-        r lpush list2 b
-        $rd blpop list1 list2 list2 list1 0
-        assert_equal [$rd read] {list1 a}
-        $rd blpop list1 list2 list2 list1 0
-        assert_equal [$rd read] {list2 b}
-    }
-
-    test "BLPOP with variadic LPUSH" {
-        set rd [redis_deferring_client]
-        r del blist target
-        if {$::valgrind} {after 100}
-        $rd blpop blist 0
-        if {$::valgrind} {after 100}
-        assert_equal 2 [r lpush blist foo bar]
-        if {$::valgrind} {after 100}
-        assert_equal {blist bar} [$rd read]
-        assert_equal foo [lindex [r lrange blist 0 -1] 0]
-    }
-
-    # test "BRPOPLPUSH with zero timeout should block indefinitely" {
-    #     set rd [redis_deferring_client]
-    #     r del blist target
-    #     $rd brpoplpush blist target 0
-    #     after 1000
-    #     r rpush blist foo
-    #     assert_equal foo [$rd read]
-    #     assert_equal {foo} [r lrange target 0 -1]
-    # }
-
-    # test "BRPOPLPUSH with a client BLPOPing the target list" {
-    #     set rd [redis_deferring_client]
-    #     set rd2 [redis_deferring_client]
-    #     r del blist target
-    #     $rd2 blpop target 0
-    #     $rd brpoplpush blist target 0
-    #     after 1000
-    #     r rpush blist foo
-    #     assert_equal foo [$rd read]
-    #     assert_equal {target foo} [$rd2 read]
-    #     assert_equal 0 [r exists target]
-    # }
-
-    # test "BRPOPLPUSH with wrong source type" {
-    #     set rd [redis_deferring_client]
-    #     r del blist target
-    #     r set blist nolist
-    #     $rd brpoplpush blist target 1
-    #     assert_error "*WRONGTYPE*" {$rd read}
-    # }
-
-    # test "BRPOPLPUSH with wrong destination type" {
-    #     set rd [redis_deferring_client]
-    #     r del blist target
-    #     r set target nolist
-    #     r lpush blist foo
-    #     $rd brpoplpush blist target 1
-    #     assert_error "*WRONGTYPE*" {$rd read}
-
-    #     set rd [redis_deferring_client]
-    #     r del blist target
-    #     r set target nolist
-    #     $rd brpoplpush blist target 0
-    #     after 1000
-    #     r rpush blist foo
-    #     assert_error "*WRONGTYPE*" {$rd read}
-    #     assert_equal {foo} [r lrange blist 0 -1]
-    # }
-
-    # test "BRPOPLPUSH maintains order of elements after failure" {
-    #     set rd [redis_deferring_client]
-    #     r del blist target
-    #     r set target nolist
-    #     $rd brpoplpush blist target 0
-    #     r rpush blist a b c
-    #     assert_error "*WRONGTYPE*" {$rd read}
-    #     r lrange blist 0 -1
-    # } {a b c}
-
-    # test "BRPOPLPUSH with multiple blocked clients" {
-    #     set rd1 [redis_deferring_client]
-    #     set rd2 [redis_deferring_client]
-    #     r del blist target1 target2
-    #     r set target1 nolist
-    #     $rd1 brpoplpush blist target1 0
-    #     $rd2 brpoplpush blist target2 0
-    #     r lpush blist foo
-
-    #     assert_error "*WRONGTYPE*" {$rd1 read}
-    #     assert_equal {foo} [$rd2 read]
-    #     assert_equal {foo} [r lrange target2 0 -1]
-    # }
-
-    # test "Linked BRPOPLPUSH" {
-    #   set rd1 [redis_deferring_client]
-    #   set rd2 [redis_deferring_client]
-    #   r del list1 list2 list3
-    #   $rd1 brpoplpush list1 list2 0
-    #   $rd2 brpoplpush list2 list3 0
-    #   r rpush list1 foo
-    #   assert_equal {} [r lrange list1 0 -1]
-    #   assert_equal {} [r lrange list2 0 -1]
-    #   assert_equal {foo} [r lrange list3 0 -1]
-    # }
-
-    # test "Circular BRPOPLPUSH" {
-    #   set rd1 [redis_deferring_client]
-    #   set rd2 [redis_deferring_client]
-    #   r del list1 list2
-    #   $rd1 brpoplpush list1 list2 0
-    #   $rd2 brpoplpush list2 list1 0
-    #   r rpush list1 foo
-    #   assert_equal {foo} [r lrange list1 0 -1]
-    #   assert_equal {} [r lrange list2 0 -1]
-    # }
-
-    # test "Self-referential BRPOPLPUSH" {
-    #   set rd [redis_deferring_client]
-    #   r del blist
-    #   $rd brpoplpush blist blist 0
-    #   r rpush blist foo
-    #   assert_equal {foo} [r lrange blist 0 -1]
-    # }
-
-    # test {BRPOPLPUSH timeout} {
-    #   set rd [redis_deferring_client]
-
-    #   $rd brpoplpush foo_list bar_list 1
-    #   after 2000
-    #   $rd read
-    # } {}
-
-    foreach {pop} {BLPOP BRPOP} {
-        test "$pop: with single empty list argument" {
-            set rd [redis_deferring_client]
-            r del blist1
-            $rd $pop blist1 1
-            r rpush blist1 foo
-            assert_equal {blist1 foo} [$rd read]
-            assert_equal 0 [r exists blist1]
-        }
-
-        test "$pop: with negative timeout" {
-            set rd [redis_deferring_client]
-            $rd $pop blist1 -1
-            assert_error "*negative*" {$rd read}
-        }
-
-        # test "$pop: with non-integer timeout" {
-        #     set rd [redis_deferring_client]
-        #     $rd $pop blist1 1.1
-        #     assert_error "ERR*not an integer*" {$rd read}
-        # }
-
-        test "$pop: with zero timeout should block indefinitely" {
-            # To test this, use a timeout of 0 and wait a second.
-            # The blocking pop should still be waiting for a push.
-            set rd [redis_deferring_client]
-            $rd $pop blist1 0
-            after 1000
-            r rpush blist1 foo
-            assert_equal {blist1 foo} [$rd read]
-        }
-
-        test "$pop: second argument is not a list" {
-            set rd [redis_deferring_client]
-            r del blist1 blist2
-            r set blist2 nolist
-            $rd $pop blist1 blist2 1
-            assert_error "*WRONGTYPE*" {$rd read}
-        }
-
-        test "$pop: timeout" {
-            set rd [redis_deferring_client]
-            r del blist1 blist2
-            $rd $pop blist1 blist2 1
-            assert_equal {} [$rd read]
-        }
-
-        test "$pop: arguments are empty" {
-            set rd [redis_deferring_client]
-            r del blist1 blist2
-
-            $rd $pop blist1 blist2 1
-            r rpush blist1 foo
-            assert_equal {blist1 foo} [$rd read]
-            assert_equal 0 [r exists blist1]
-            assert_equal 0 [r exists blist2]
-
-            $rd $pop blist1 blist2 1
-            r rpush blist2 foo
-            assert_equal {blist2 foo} [$rd read]
-            assert_equal 0 [r exists blist1]
-            assert_equal 0 [r exists blist2]
-        }
-    }
-
-    test {LPUSHX, RPUSHX - generic} {
-        r del xlist
-        assert_equal 0 [r lpushx xlist a]
-        assert_equal 0 [r llen xlist]
-        assert_equal 0 [r rpushx xlist a]
-        assert_equal 0 [r llen xlist]
-    }
-
-    foreach {type large} [array get largevalue] {
-        test "LPUSHX, RPUSHX - $type" {
-            create_list xlist "$large c"
-            assert_equal 3 [r rpushx xlist d]
-            assert_equal 4 [r lpushx xlist a]
-            assert_equal 6 [r rpushx xlist 42 x]
-            assert_equal 9 [r lpushx xlist y3 y2 y1]
-            assert_equal "y1 y2 y3 a $large c d 42 x" [r lrange xlist 0 -1]
-        }
-
-        test "LINSERT - $type" {
-            create_list xlist "a $large c d"
-            assert_equal 5 [r linsert xlist before c zz] "before c"
-            assert_equal "a $large zz c d" [r lrange xlist 0 10] "lrangeA"
-            assert_equal 6 [r linsert xlist after c yy] "after c"
-            assert_equal "a $large zz c yy d" [r lrange xlist 0 10] "lrangeB"
-            assert_equal 7 [r linsert xlist after d dd] "after d"
-            assert_equal -1 [r linsert xlist after bad ddd] "after bad"
-            assert_equal "a $large zz c yy d dd" [r lrange xlist 0 10] 
"lrangeC"
-            assert_equal 8 [r linsert xlist before a aa] "before a"
-            assert_equal -1 [r linsert xlist before bad aaa] "before bad"
-            assert_equal "aa a $large zz c yy d dd" [r lrange xlist 0 10] 
"lrangeD"
-
-            # check inserting integer encoded value
-            assert_equal 9 [r linsert xlist before aa 42] "before aa"
-            assert_equal 42 [r lrange xlist 0 0] "lrangeE"
-        }
-    }
-
-    test {LINSERT raise error on bad syntax} {
-        catch {[r linsert xlist aft3r aa 42]} e
-        set e
-    } {*syntax*error*}
-
-    foreach {type num} {quicklist 250 quicklist 500} {
-        proc check_numbered_list_consistency {key} {
-            set len [r llen $key]
-            for {set i 0} {$i < $len} {incr i} {
-                assert_equal $i [r lindex $key $i]
-                assert_equal [expr $len-1-$i] [r lindex $key [expr (-$i)-1]]
-            }
-        }
-
-        proc check_random_access_consistency {key} {
-            set len [r llen $key]
-            for {set i 0} {$i < $len} {incr i} {
-                set rint [expr int(rand()*$len)]
-                assert_equal $rint [r lindex $key $rint]
-                assert_equal [expr $len-1-$rint] [r lindex $key [expr 
(-$rint)-1]]
-            }
-        }
-
-        test "LINDEX consistency test - $type" {
-            r del mylist
-            for {set i 0} {$i < $num} {incr i} {
-                r rpush mylist $i
-            }
-            #assert_encoding $type mylist
-            check_numbered_list_consistency mylist
-        }
-
-        test "LINDEX random access - $type" {
-            #assert_encoding $type mylist
-            check_random_access_consistency mylist
-        }
-
-        test "Check if list is still ok after a DEBUG RELOAD - $type" {
-            #assert_encoding $type mylist
-            check_numbered_list_consistency mylist
-            check_random_access_consistency mylist
-        }
-    }
-
-    test {LLEN against non-list value error} {
-        r del mylist
-        r set mylist foobar
-        assert_error *WRONGTYPE* {r llen mylist}
-    }
-
-    test {LLEN against non existing key} {
-        assert_equal 0 [r llen not-a-key]
-    }
-
-    test {LINDEX against non-list value error} {
-        assert_error *WRONGTYPE* {r lindex mylist 0}
-    }
-
-    test {LINDEX against non existing key} {
-        assert_equal "" [r lindex not-a-key 10]
-    }
-
-    test {LPUSH against non-list value error} {
-        assert_error *WRONGTYPE* {r lpush mylist 0}
-    }
-
-    test {RPUSH against non-list value error} {
-        assert_error *WRONGTYPE* {r rpush mylist 0}
-    }
-
-    foreach {type large} [array get largevalue] {
-        test "RPOPLPUSH base case - $type" {
-            r del mylist1 mylist2
-            create_list mylist1 "a $large c d"
-            assert_equal d [r rpoplpush mylist1 mylist2]
-            assert_equal c [r rpoplpush mylist1 mylist2]
-            assert_equal "a $large" [r lrange mylist1 0 -1]
-            assert_equal "c d" [r lrange mylist2 0 -1]
-            #assert_encoding quicklist mylist2
-        }
-
-        test "RPOPLPUSH with the same list as src and dst - $type" {
-            create_list mylist "a $large c"
-            assert_equal "a $large c" [r lrange mylist 0 -1]
-            assert_equal c [r rpoplpush mylist mylist]
-            assert_equal "c a $large" [r lrange mylist 0 -1]
-        }
-
-        foreach {othertype otherlarge} [array get largevalue] {
-            test "RPOPLPUSH with $type source and existing target $othertype" {
-                create_list srclist "a b c $large"
-                create_list dstlist "$otherlarge"
-                assert_equal $large [r rpoplpush srclist dstlist]
-                assert_equal c [r rpoplpush srclist dstlist]
-                assert_equal "a b" [r lrange srclist 0 -1]
-                assert_equal "c $large $otherlarge" [r lrange dstlist 0 -1]
-
-                # When we rpoplpush'ed a large value, dstlist should be
-                # converted to the same encoding as srclist.
-                if {$type eq "linkedlist"} {
-                    #assert_encoding quicklist dstlist
-                }
-            }
-        }
-    }
-
-    test {RPOPLPUSH against non existing key} {
-        r del srclist dstlist
-        assert_equal {} [r rpoplpush srclist dstlist]
-        assert_equal 0 [r exists srclist]
-        assert_equal 0 [r exists dstlist]
-    }
-
-    test {RPOPLPUSH against non list src key} {
-        r del srclist dstlist
-        r set srclist x
-        assert_error *WRONGTYPE* {r rpoplpush srclist dstlist}
-        assert_type string srclist
-        assert_equal 0 [r exists newlist]
-    }
-
-    test {RPOPLPUSH against non list dst key} {
-        create_list srclist {a b c d}
-        r set dstlist x
-        assert_error *WRONGTYPE* {r rpoplpush srclist dstlist}
-        assert_type string dstlist
-        assert_equal {a b c d} [r lrange srclist 0 -1]
-    }
-
-    test {RPOPLPUSH against non existing src key} {
-        r del srclist dstlist
-        assert_equal {} [r rpoplpush srclist dstlist]
-    } {}
-
-    foreach {type large} [array get largevalue] {
-        test "Basic LPOP/RPOP - $type" {
-            create_list mylist "$large 1 2"
-            assert_equal $large [r lpop mylist]
-            assert_equal 2 [r rpop mylist]
-            assert_equal 1 [r lpop mylist]
-            assert_equal 0 [r llen mylist]
-
-            # pop on empty list
-            assert_equal {} [r lpop mylist]
-            assert_equal {} [r rpop mylist]
-        }
-    }
-
-    test {LPOP/RPOP against non list value} {
-        r set notalist foo
-        assert_error *WRONGTYPE* {r lpop notalist}
-        assert_error *WRONGTYPE* {r rpop notalist}
-    }
-
-    test "LPOP/RPOP with wrong number of arguments" {
-        assert_error {*wrong number of arguments*} {r lpop key 1 1}
-        assert_error {*wrong number of arguments*} {r rpop key 2 2}
-    }
-
-    test {RPOP/LPOP with the optional count argument} {
-        assert_equal 7 [r lpush listcount aa bb cc dd ee ff gg]
-        assert_equal {gg} [r lpop listcount 1]
-        assert_equal {ff ee} [r lpop listcount 2]
-        assert_equal {aa bb} [r rpop listcount 2]
-        assert_equal {cc} [r rpop listcount 1]
-        assert_equal {dd} [r rpop listcount 123]
-        assert_error "*ERR*range*" {r lpop forbarqaz -123}
-    }
-
-    test "LPOP/RPOP with the count 0 returns an empty array" {
-        # Make sure we can distinguish between an empty array and a null 
response
-        r readraw 1
-
-        r lpush listcount zero
-        assert_equal {*0} [r lpop listcount 0]
-        assert_equal {*0} [r rpop listcount 0]
-
-        r readraw 0
-    }
-
-    test "LPOP/RPOP against non existing key" {
-        r readraw 1
-
-        r del non_existing_key
-        assert_equal [r lpop non_existing_key] {$-1}
-        assert_equal [r rpop non_existing_key] {$-1}
-
-        r readraw 0
-    }
-
-    test "LPOP/RPOP with <count> against non existing key" {
-        r readraw 1
-
-        r del non_existing_key
-
-        assert_equal [r lpop non_existing_key 0] {*-1}
-        assert_equal [r lpop non_existing_key 1] {*-1}
-
-        assert_equal [r rpop non_existing_key 0] {*-1}
-        assert_equal [r rpop non_existing_key 1] {*-1}
-
-        r readraw 0
-    }
-
-    foreach {type num} {quicklist 250 quicklist 500} {
-        test "Mass RPOP/LPOP - $type" {
-            r del mylist
-            set sum1 0
-            for {set i 0} {$i < $num} {incr i} {
-                r lpush mylist $i
-                incr sum1 $i
-            }
-            #assert_encoding $type mylist
-            set sum2 0
-            for {set i 0} {$i < [expr $num/2]} {incr i} {
-                incr sum2 [r lpop mylist]
-                incr sum2 [r rpop mylist]
-            }
-            assert_equal $sum1 $sum2
-        }
-    }
-
-    foreach {type large} [array get largevalue] {
-        test "LRANGE basics - $type" {
-            create_list mylist "$large 1 2 3 4 5 6 7 8 9"
-            assert_equal {1 2 3 4 5 6 7 8} [r lrange mylist 1 -2]
-            assert_equal {7 8 9} [r lrange mylist -3 -1]
-            assert_equal {4} [r lrange mylist 4 4]
-        }
-
-        test "LRANGE inverted indexes - $type" {
-            create_list mylist "$large 1 2 3 4 5 6 7 8 9"
-            assert_equal {} [r lrange mylist 6 2]
-        }
-
-        test "LRANGE out of range indexes including the full list - $type" {
-            create_list mylist "$large 1 2 3"
-            assert_equal "$large 1 2 3" [r lrange mylist -1000 1000]
-        }
-
-        test "LRANGE out of range negative end index - $type" {
-            create_list mylist "$large 1 2 3"
-            assert_equal $large [r lrange mylist 0 -4]
-            assert_equal {} [r lrange mylist 0 -5]
-        }
-    }
-
-    test {LRANGE against non existing key} {
-        assert_equal {} [r lrange nosuchkey 0 1]
-    }
-
-    foreach {type large} [array get largevalue] {
-        proc trim_list {type min max} {
-            upvar 1 large large
-            r del mylist
-            create_list mylist "1 2 3 4 $large"
-            r ltrim mylist $min $max
-            r lrange mylist 0 -1
-        }
-
-        test "LTRIM basics - $type" {
-            assert_equal "1" [trim_list $type 0 0]
-            assert_equal "1 2" [trim_list $type 0 1]
-            assert_equal "1 2 3" [trim_list $type 0 2]
-            assert_equal "2 3" [trim_list $type 1 2]
-            assert_equal "2 3 4 $large" [trim_list $type 1 -1]
-            assert_equal "2 3 4" [trim_list $type 1 -2]
-            assert_equal "4 $large" [trim_list $type -2 -1]
-            assert_equal "$large" [trim_list $type -1 -1]
-            assert_equal "1 2 3 4 $large" [trim_list $type -5 -1]
-            assert_equal "1 2 3 4 $large" [trim_list $type -10 10]
-            assert_equal "1 2 3 4 $large" [trim_list $type 0 5]
-            assert_equal "1 2 3 4 $large" [trim_list $type 0 10]
-        }
-
-        test "LTRIM out of range negative end index - $type" {
-            assert_equal {1} [trim_list $type 0 -5]
-            assert_equal {} [trim_list $type 0 -6]
-        }
-
-        test "LTRIM lrem elements after ltrim list - $type" {
-            create_list myotherlist "0 1 2 3 4 3 6 7 3 9"
-            assert_equal "OK" [r ltrim myotherlist 2 -3]
-            assert_equal "2 3 4 3 6 7" [r lrange myotherlist 0 -1]
-            assert_equal 2 [r lrem myotherlist 4 3]
-            assert_equal "2 4 6 7" [r lrange myotherlist 0 -1]
-        }
-
-        test "LTRIM linsert elements after ltrim list - $type" {
-            create_list myotherlist1 "0 1 2 3 4 3 6 7 3 9"
-            assert_equal "OK" [r ltrim myotherlist1 2 -3]
-            assert_equal "2 3 4 3 6 7" [r lrange myotherlist1 0 -1]
-            assert_equal -1 [r linsert myotherlist1 before 9 0]
-            assert_equal 7 [r linsert myotherlist1 before 4 0]
-            assert_equal "2 3 0 4 3 6 7" [r lrange myotherlist1 0 -1]
-        }
-    }
-
-    foreach {type large} [array get largevalue] {
-        test "LSET - $type" {
-            create_list mylist "99 98 $large 96 95"
-            r lset mylist 1 foo
-            r lset mylist -1 bar
-            assert_equal "99 foo $large 96 bar" [r lrange mylist 0 -1]
-        }
-
-        test "LSET out of range index - $type" {
-            assert_error ERR*range* {r lset mylist 10 foo}
-        }
-    }
-
-    test {LSET against non existing key} {
-        assert_error ERR*NotFound* {r lset nosuchkey 10 foo}
-    }
-
-    test {LSET against non list value} {
-        r set nolist foobar
-        assert_error *WRONGTYPE* {r lset nolist 0 foo}
-    }
-
-    foreach {type e} [array get largevalue] {
-        test "LREM remove all the occurrences - $type" {
-            create_list mylist "$e foo bar foobar foobared zap bar test foo"
-            assert_equal 2 [r lrem mylist 0 bar]
-            assert_equal "$e foo foobar foobared zap test foo" [r lrange 
mylist 0 -1]
-        }
-
-        test "LREM remove the first occurrence - $type" {
-            assert_equal 1 [r lrem mylist 1 foo]
-            assert_equal "$e foobar foobared zap test foo" [r lrange mylist 0 
-1]
-        }
-
-        test "LREM remove non existing element - $type" {
-            assert_equal 0 [r lrem mylist 1 nosuchelement]
-            assert_equal "$e foobar foobared zap test foo" [r lrange mylist 0 
-1]
-        }
-
-        test "LREM starting from tail with negative count - $type" {
-            create_list mylist "$e foo bar foobar foobared zap bar test foo 
foo"
-            assert_equal 1 [r lrem mylist -1 bar]
-            assert_equal "$e foo bar foobar foobared zap test foo foo" [r 
lrange mylist 0 -1]
-        }
-
-        test "LREM starting from tail with negative count (2) - $type" {
-            assert_equal 2 [r lrem mylist -2 foo]
-            assert_equal "$e foo bar foobar foobared zap test" [r lrange 
mylist 0 -1]
-        }
-
-        test "LREM deleting objects that may be int encoded - $type" {
-            create_list myotherlist "$e 1 2 3"
-            assert_equal 1 [r lrem myotherlist 1 2]
-            assert_equal 3 [r llen myotherlist]
-        }
-
-        test "LREM remove elements in repeating list - $type" {
-            create_list myotherlist1 "$e a b c d e f a f a f"
-            assert_equal 1 [r lrem myotherlist1 1 f]
-            assert_equal "$e a b c d e a f a f" [r lrange myotherlist1 0 -1]
-            assert_equal 2 [r lrem myotherlist1 0 f]
-            assert_equal "$e a b c d e a a" [r lrange myotherlist1 0 -1]
-        }
-    }
-
-    # test "Regression for bug 593 - chaining BRPOPLPUSH with other blocking 
cmds" {
-    #     set rd1 [redis_deferring_client]
-    #     set rd2 [redis_deferring_client]
-
-    #     $rd1 brpoplpush a b 0
-    #     $rd1 brpoplpush a b 0
-    #     $rd2 brpoplpush b c 0
-    #     after 1000
-    #     r lpush a data
-    #     $rd1 close
-    #     $rd2 close
-    #     r ping
-    # } {PONG}
-
-    test {Test LMOVE on different keys} {
-        r RPUSH list1{t} "1"
-        r RPUSH list1{t} "2"
-        r RPUSH list1{t} "3"
-        r RPUSH list1{t} "4"
-        r RPUSH list1{t} "5"
-
-        r LMOVE list1{t} list2{t} RIGHT LEFT
-        r LMOVE list1{t} list2{t} LEFT RIGHT
-        assert_equal [r llen list1{t}] 3
-        assert_equal [r llen list2{t}] 2
-        assert_equal [r lrange list1{t} 0 -1] {2 3 4}
-        assert_equal [r lrange list2{t} 0 -1] {5 1}
-    }
-
-    foreach from {LEFT RIGHT} {
-        foreach to {LEFT RIGHT} {
-            test "LMOVE $from $to on the list node" {
-                    r del target_key{t}
-                    r rpush target_key{t} 1
-
-                    set rd [redis_deferring_client]
-                    create_list list{t} "a b c d"
-                    $rd lmove list{t} target_key{t} $from $to
-                    set elem [$rd read]
-
-                    if {$from eq "RIGHT"} {
-                        assert_equal d $elem
-                        assert_equal "a b c" [r lrange list{t} 0 -1]
-                    } else {
-                        assert_equal a $elem
-                        assert_equal "b c d" [r lrange list{t} 0 -1]
-                    }
-                    if {$to eq "RIGHT"} {
-                        assert_equal $elem [r rpop target_key{t}]
-                    } else {
-                        assert_equal $elem [r lpop target_key{t}]
-                    }
-
-                    $rd close
-                }
-            }
-        }
-}

Reply via email to