Skip to content

Commit

Permalink
Add bitfield type size validation
Browse files Browse the repository at this point in the history
  • Loading branch information
Brett Norris committed Apr 30, 2018
1 parent 700ec6d commit 84305ce
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 26 deletions.
57 changes: 31 additions & 26 deletions lib/mock_redis/string_methods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,39 +24,48 @@ def bitfield(*args)
while args.length > 0 do
command = args.shift.to_s

unless command == "overflow"
type, offset = args.shift(2)

is_signed, type_size = type.slice(0) == "i", type[1..-1].to_i
if command == "overflow"
new_overflow_method = args.shift.to_s.downcase

if offset.to_s[0] == "#"
offset = offset[1..-1].to_i * type_size
unless ["wrap", "sat", "fail"].include? new_overflow_method
raise Redis::CommandError, 'ERR Invalid OVERFLOW type specified'
end

bits = []
overflow_method = new_overflow_method
next
end

type_size.times do |i|
bits.push(getbit(key, offset + i))
end
type, offset = args.shift(2)

if is_signed
val = twos_complement_decode(bits)
else
val = bits.join("").to_i(2)
end
is_signed, type_size = type.slice(0) == "i", type[1..-1].to_i

if (type_size > 64 && is_signed) || (type_size >= 64 && !is_signed)
raise Redis::CommandError, "ERR Invalid bitfield type. Use something like i16 u8. Note that u64 is not supported but i64 is."
end

if offset.to_s[0] == "#"
offset = offset[1..-1].to_i * type_size
end

bits = []

type_size.times do |i|
bits.push(getbit(key, offset + i))
end

if is_signed
val = twos_complement_decode(bits)
else
val = bits.join("").to_i(2)
end

case command
when "get"
output.push(val)
when "overflow"
new_overflow_method = args.shift.to_s.downcase

unless ["wrap", "sat", "fail"].include? new_overflow_method
raise Redis::CommandError, 'ERR Invalid OVERFLOW type specified'
end
when "set"
output.push(val)

overflow_method = new_overflow_method
set_value(key, args.shift.to_i, is_signed, type_size, offset)
when "incrby"
new_val = val + args.shift.to_i

Expand Down Expand Up @@ -91,10 +100,6 @@ def bitfield(*args)

set_value(key, new_val, is_signed, type_size, offset) if new_val
output.push(new_val)
when "set"
output.push(val)

set_value(key, args.shift.to_i, is_signed, type_size, offset)
end
end

Expand Down
9 changes: 9 additions & 0 deletions spec/commands/bitfield_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@
:get, "i8", "#1",
:get, "i8", "#2").should == [78, 104, -59]
end

it "shows an error with an invalid type" do
expect { @redises.bitfield(@key, :get, "u64", 0) }.to raise_error
expect { @redises.bitfield(@key, :get, "i128", 0) }.to raise_error(Redis::CommandError)
end

it "returns a value with an i64 type" do
expect { @redises.bitfield(@key, :get, "i64", 0) }.to_not raise_error(Redis::CommandError)
end
end

context "with a :set command" do
Expand Down

0 comments on commit 84305ce

Please sign in to comment.