]> git.saurik.com Git - redis.git/blob - tests/unit/bitops.tcl
Copyright date fixed in COPYING file.
[redis.git] / tests / unit / bitops.tcl
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 } {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 }