]>
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 {BITOP NOT (empty string)} { | |
77 | r set s "" | |
78 | r bitop not dest s | |
79 | r get dest | |
80 | } {} | |
81 | ||
82 | test {BITOP NOT (known string)} { | |
83 | r set s "\xaa\x00\xff\x55" | |
84 | r bitop not dest s | |
85 | r get dest | |
86 | } "\x55\xff\x00\xaa" | |
87 | ||
88 | test {BITOP where dest and target are the same key} { | |
89 | r set s "\xaa\x00\xff\x55" | |
90 | r bitop not s s | |
91 | r get s | |
92 | } "\x55\xff\x00\xaa" | |
93 | ||
94 | test {BITOP AND|OR|XOR don't change the string with single input key} { | |
95 | r set a "\x01\x02\xff" | |
96 | r bitop and res1 a | |
97 | r bitop or res2 a | |
98 | r bitop xor res3 a | |
99 | list [r get res1] [r get res2] [r get res3] | |
100 | } [list "\x01\x02\xff" "\x01\x02\xff" "\x01\x02\xff"] | |
101 | ||
102 | test {BITOP missing key is considered a stream of zero} { | |
103 | r set a "\x01\x02\xff" | |
104 | r bitop and res1 no-suck-key a | |
105 | r bitop or res2 no-suck-key a no-such-key | |
106 | r bitop xor res3 no-such-key a | |
107 | list [r get res1] [r get res2] [r get res3] | |
108 | } [list "\x00\x00\x00" "\x01\x02\xff" "\x01\x02\xff"] | |
109 | ||
110 | test {BITOP shorter keys are zero-padded to the key with max length} { | |
111 | r set a "\x01\x02\xff\xff" | |
112 | r set b "\x01\x02\xff" | |
113 | r bitop and res1 a b | |
114 | r bitop or res2 a b | |
115 | r bitop xor res3 a b | |
116 | list [r get res1] [r get res2] [r get res3] | |
117 | } [list "\x01\x02\xff\x00" "\x01\x02\xff\xff" "\x00\x00\x00\xff"] | |
118 | ||
119 | foreach op {and or xor} { | |
120 | test "BITOP $op fuzzing" { | |
121 | for {set i 0} {$i < 10} {incr i} { | |
122 | r flushall | |
123 | set vec {} | |
124 | set veckeys {} | |
125 | set numvec [expr {[randomInt 10]+1}] | |
126 | for {set j 0} {$j < $numvec} {incr j} { | |
127 | set str [randstring 0 1000] | |
128 | lappend vec $str | |
129 | lappend veckeys vector_$j | |
130 | r set vector_$j $str | |
131 | } | |
132 | r bitop $op target {*}$veckeys | |
133 | assert_equal [r get target] [simulate_bit_op $op {*}$vec] | |
134 | } | |
135 | } | |
136 | } | |
137 | ||
138 | test {BITOP NOT fuzzing} { | |
139 | for {set i 0} {$i < 10} {incr i} { | |
140 | r flushall | |
141 | set str [randstring 0 1000] | |
142 | r set str $str | |
143 | r bitop not target str | |
144 | assert_equal [r get target] [simulate_bit_op not $str] | |
145 | } | |
146 | } | |
147 | ||
148 | test {BITOP with integer encoded source objects} { | |
149 | r set a 1 | |
150 | r set b 2 | |
151 | r bitop xor dest a b a | |
152 | r get dest | |
153 | } {2} | |
154 | ||
155 | test {BITOP with non string source key} { | |
156 | r del c | |
157 | r set a 1 | |
158 | r set b 2 | |
159 | r lpush c foo | |
160 | catch {r bitop xor dest a b c d} e | |
161 | set e | |
162 | } {*ERR*} | |
163 | ||
164 | test {BITOP with empty string after non empty string (issue #529)} { | |
165 | r flushdb | |
166 | 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" | |
167 | r bitop or x a b | |
168 | } {32} | |
169 | } |