xref: /redis-3.2.3/tests/unit/bitops.tcl (revision 40f822da)
1# Compare Redis commadns against Tcl implementations of the same commands.
2proc count_bits s {
3    binary scan $s b* bits
4    string length [regsub -all {0} $bits {}]
5}
6
7proc simulate_bit_op {op args} {
8    set maxlen 0
9    set j 0
10    set count [llength $args]
11    foreach a $args {
12        binary scan $a b* bits
13        set b($j) $bits
14        if {[string length $bits] > $maxlen} {
15            set maxlen [string length $bits]
16        }
17        incr j
18    }
19    for {set j 0} {$j < $count} {incr j} {
20        if {[string length $b($j)] < $maxlen} {
21            append b($j) [string repeat 0 [expr $maxlen-[string length $b($j)]]]
22        }
23    }
24    set out {}
25    for {set x 0} {$x < $maxlen} {incr x} {
26        set bit [string range $b(0) $x $x]
27        if {$op eq {not}} {set bit [expr {!$bit}]}
28        for {set j 1} {$j < $count} {incr j} {
29            set bit2 [string range $b($j) $x $x]
30            switch $op {
31                and {set bit [expr {$bit & $bit2}]}
32                or  {set bit [expr {$bit | $bit2}]}
33                xor {set bit [expr {$bit ^ $bit2}]}
34            }
35        }
36        append out $bit
37    }
38    binary format b* $out
39}
40
41start_server {tags {"bitops"}} {
42    test {BITCOUNT returns 0 against non existing key} {
43        r bitcount no-key
44    } 0
45
46    catch {unset num}
47    foreach vec [list "" "\xaa" "\x00\x00\xff" "foobar" "123"] {
48        incr num
49        test "BITCOUNT against test vector #$num" {
50            r set str $vec
51            assert {[r bitcount str] == [count_bits $vec]}
52        }
53    }
54
55    test {BITCOUNT fuzzing} {
56        for {set j 0} {$j < 100} {incr j} {
57            set str [randstring 0 3000]
58            r set str $str
59            assert {[r bitcount str] == [count_bits $str]}
60        }
61    }
62
63    test {BITCOUNT with start, end} {
64        r set s "foobar"
65        assert_equal [r bitcount s 0 -1] [count_bits "foobar"]
66        assert_equal [r bitcount s 1 -2] [count_bits "ooba"]
67        assert_equal [r bitcount s -2 1] [count_bits ""]
68        assert_equal [r bitcount s 0 1000] [count_bits "foobar"]
69    }
70
71    test {BITCOUNT syntax error #1} {
72        catch {r bitcount s 0} e
73        set e
74    } {ERR*syntax*}
75
76    test {BITCOUNT regression test for github issue #582} {
77        r del str
78        r setbit foo 0 1
79        if {[catch {r bitcount foo 0 4294967296} e]} {
80            assert_match {*ERR*out of range*} $e
81            set _ 1
82        } else {
83            set e
84        }
85    } {1}
86
87    test {BITOP NOT (empty string)} {
88        r set s ""
89        r bitop not dest s
90        r get dest
91    } {}
92
93    test {BITOP NOT (known string)} {
94        r set s "\xaa\x00\xff\x55"
95        r bitop not dest s
96        r get dest
97    } "\x55\xff\x00\xaa"
98
99    test {BITOP where dest and target are the same key} {
100        r set s "\xaa\x00\xff\x55"
101        r bitop not s s
102        r get s
103    } "\x55\xff\x00\xaa"
104
105    test {BITOP AND|OR|XOR don't change the string with single input key} {
106        r set a "\x01\x02\xff"
107        r bitop and res1 a
108        r bitop or  res2 a
109        r bitop xor res3 a
110        list [r get res1] [r get res2] [r get res3]
111    } [list "\x01\x02\xff" "\x01\x02\xff" "\x01\x02\xff"]
112
113    test {BITOP missing key is considered a stream of zero} {
114        r set a "\x01\x02\xff"
115        r bitop and res1 no-suck-key a
116        r bitop or  res2 no-suck-key a no-such-key
117        r bitop xor res3 no-such-key a
118        list [r get res1] [r get res2] [r get res3]
119    } [list "\x00\x00\x00" "\x01\x02\xff" "\x01\x02\xff"]
120
121    test {BITOP shorter keys are zero-padded to the key with max length} {
122        r set a "\x01\x02\xff\xff"
123        r set b "\x01\x02\xff"
124        r bitop and res1 a b
125        r bitop or  res2 a b
126        r bitop xor res3 a b
127        list [r get res1] [r get res2] [r get res3]
128    } [list "\x01\x02\xff\x00" "\x01\x02\xff\xff" "\x00\x00\x00\xff"]
129
130    foreach op {and or xor} {
131        test "BITOP $op fuzzing" {
132            for {set i 0} {$i < 10} {incr i} {
133                r flushall
134                set vec {}
135                set veckeys {}
136                set numvec [expr {[randomInt 10]+1}]
137                for {set j 0} {$j < $numvec} {incr j} {
138                    set str [randstring 0 1000]
139                    lappend vec $str
140                    lappend veckeys vector_$j
141                    r set vector_$j $str
142                }
143                r bitop $op target {*}$veckeys
144                assert_equal [r get target] [simulate_bit_op $op {*}$vec]
145            }
146        }
147    }
148
149    test {BITOP NOT fuzzing} {
150        for {set i 0} {$i < 10} {incr i} {
151            r flushall
152            set str [randstring 0 1000]
153            r set str $str
154            r bitop not target str
155            assert_equal [r get target] [simulate_bit_op not $str]
156        }
157    }
158
159    test {BITOP with integer encoded source objects} {
160        r set a 1
161        r set b 2
162        r bitop xor dest a b a
163        r get dest
164    } {2}
165
166    test {BITOP with non string source key} {
167        r del c
168        r set a 1
169        r set b 2
170        r lpush c foo
171        catch {r bitop xor dest a b c d} e
172        set e
173    } {WRONGTYPE*}
174
175    test {BITOP with empty string after non empty string (issue #529)} {
176        r flushdb
177        r set a "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
178        r bitop or x a b
179    } {32}
180}
181