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