test and fix for BSON w/ negative integers. raise RangeError for out of range ints

This commit is contained in:
Mike Dirolf 2009-05-15 11:19:13 -04:00
parent a9aa5e5271
commit 37d6e16fe7
3 changed files with 38 additions and 1 deletions

View File

@ -151,6 +151,10 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
switch(TYPE(value)) { switch(TYPE(value)) {
case T_BIGNUM: case T_BIGNUM:
{ {
if (rb_funcall(value, rb_intern(">"), 1, INT2NUM(2147483647)) == Qtrue ||
rb_funcall(value, rb_intern("<"), 1, INT2NUM(-2147483648)) == Qtrue) {
rb_raise(rb_eRangeError, "MongoDB can only handle 4-byte ints - try converting to a double before saving");
}
write_name_and_type(buffer, key, 0x10); write_name_and_type(buffer, key, 0x10);
VALUE as_f = rb_funcall(value, rb_intern("to_f"), 0); VALUE as_f = rb_funcall(value, rb_intern("to_f"), 0);
int int_value = NUM2LL(as_f); int int_value = NUM2LL(as_f);

View File

@ -248,7 +248,10 @@ class BSON
end end
def deserialize_number_int_data(buf) def deserialize_number_int_data(buf)
buf.get_int # sometimes ruby makes me angry... why would the same code pack as signed
# but unpack as unsigned
unsigned = buf.get_int
unsigned >= 2**32 / 2 ? unsigned - 2**32 : unsigned
end end
def deserialize_object_data(buf) def deserialize_object_data(buf)
@ -387,6 +390,9 @@ class BSON
if type == NUMBER if type == NUMBER
buf.put_double(val) buf.put_double(val)
else else
if val > 2**32 / 2 - 1 or val < -2**32 / 2
raise RangeError.new "MongoDB can only handle 4-byte ints - try converting to a double before saving"
end
buf.put_int(val) buf.put_int(val)
end end
end end

View File

@ -36,6 +36,18 @@ class BSONTest < Test::Unit::TestCase
doc = {'doc' => 42} doc = {'doc' => 42}
@b.serialize(doc) @b.serialize(doc)
assert_equal doc, @b.deserialize assert_equal doc, @b.deserialize
doc = {"doc" => -5600}
@b.serialize(doc)
assert_equal doc, @b.deserialize
doc = {"doc" => 2147483647}
@b.serialize(doc)
assert_equal doc, @b.deserialize
doc = {"doc" => -2147483648}
@b.serialize(doc)
assert_equal doc, @b.deserialize
end end
def test_ordered_hash def test_ordered_hash
@ -195,6 +207,21 @@ class BSONTest < Test::Unit::TestCase
0x00, 0x00, 0x00]) 0x00, 0x00, 0x00])
end end
def test_overflow
doc = {"x" => 2**45}
assert_raise RangeError do
@b.serialize(doc)
end
doc = {"x" => 2147483647}
assert_equal doc, @b.deserialize(@b.serialize(doc).to_a)
doc["x"] = doc["x"] + 1
assert_raise RangeError do
@b.serialize(doc)
end
end
def test_do_not_change_original_object def test_do_not_change_original_object
val = OrderedHash.new val = OrderedHash.new
val['not_id'] = 1 val['not_id'] = 1