Skip to content

Commit 89a3ab7

Browse files
committed
Fix error with bitcount support
1 parent f71f3d8 commit 89a3ab7

File tree

2 files changed

+32
-9
lines changed

2 files changed

+32
-9
lines changed

fakeredis/commands_mixins/bitmap_mixin.py

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from fakeredis import _msgs as msgs
22
from fakeredis._commands import (command, Key, Int, BitOffset, BitValue, fix_range_string)
3-
from fakeredis._helpers import SimpleError
3+
from fakeredis._helpers import SimpleError, casematch
44

55

66
class BitmapCommandsMixin:
@@ -11,15 +11,28 @@ class BitmapCommandsMixin:
1111
def bitcount(self, key, *args):
1212
# Redis checks the argument count before decoding integers. That's why
1313
# we can't declare them as Int.
14-
if args:
15-
if len(args) != 2:
16-
raise SimpleError(msgs.SYNTAX_ERROR_MSG)
17-
start = Int.decode(args[0])
18-
end = Int.decode(args[1])
19-
start, end = fix_range_string(start, end, len(key.value))
20-
value = key.value[start:end]
21-
else:
14+
if len(args) == 0:
2215
value = key.value
16+
return bin(int.from_bytes(value, 'little')).count('1')
17+
18+
if not 2 <= len(args) <= 3:
19+
raise SimpleError(msgs.SYNTAX_ERROR_MSG)
20+
start = Int.decode(args[0])
21+
end = Int.decode(args[1])
22+
bit_mode = False
23+
if len(args) == 3:
24+
bit_mode = casematch(args[2], b'bit')
25+
if not bit_mode and not casematch(args[2], b'byte'):
26+
raise SimpleError(msgs.SYNTAX_ERROR_MSG)
27+
28+
if bit_mode:
29+
value = key.value.decode() if key.value else ''
30+
value = list(map(int, ''.join([bin(ord(i)).lstrip('0b').rjust(8, '0') for i in value])))
31+
start, end = fix_range_string(start, end, len(value))
32+
return value[start:end].count(1)
33+
start, end = fix_range_string(start, end, len(key.value))
34+
value = key.value[start:end]
35+
2336
return bin(int.from_bytes(value, 'little')).count('1')
2437

2538
@command((Key(bytes), BitOffset))

test/test_mixins/test_bitmap_commands.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
import redis
33
import redis.client
44

5+
from test.testtools import raw_command
6+
57

68
def test_getbit(r):
79
r.setbit('foo', 3, 1)
@@ -98,6 +100,14 @@ def test_bitcount(r):
98100
assert r.bitcount('foo') == 3
99101
r.set('foo', ' ')
100102
assert r.bitcount('foo') == 1
103+
r.set('key', 'foobar')
104+
with pytest.raises(redis.ResponseError):
105+
raw_command(r, 'bitcount', 'key', '1', '2', 'dsd')
106+
assert r.bitcount('key') == 26
107+
assert r.bitcount('key', start=0, end=0) == 4
108+
assert r.bitcount('key', start=1, end=1) == 6
109+
assert r.bitcount('key', start=1, end=1, mode='byte') == 6
110+
assert r.bitcount('key', start=5, end=30, mode='bit') == 17
101111

102112

103113
def test_bitcount_wrong_type(r):

0 commit comments

Comments
 (0)