]>
Commit | Line | Data |
---|---|---|
1 | # Compare Redis commadns against Tcl implementations of the same commands. | |
2 | proc count_bits s { | |
3 | binary scan $s b* bits | |
4 | string length [regsub -all {0} $bits {}] | |
5 | } | |
6 | ||
7 | proc 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 | ||
41 | start_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 | } {*ERR*} | |
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 | } |