diff --git a/Rakefile b/Rakefile index e526d7c1d9..c90e8272f5 100644 --- a/Rakefile +++ b/Rakefile @@ -10,6 +10,7 @@ rescue LoadError end require 'rbconfig' include Config +ENV['TEST_MODE'] = 'TRUE' gem_command = "gem" gem_command = "gem1.9" if $0.match(/1\.9$/) # use gem1.9 if we used rake1.9 diff --git a/lib/mongo.rb b/lib/mongo.rb index 6f3d70273d..187f6e03cd 100644 --- a/lib/mongo.rb +++ b/lib/mongo.rb @@ -8,6 +8,8 @@ module Mongo end begin + # Need this for running test with and without c ext in Ruby 1.9. + raise LoadError if ENV['TEST_MODE'] && !ENV['C_EXT'] require 'mongo_ext/cbson' require 'mongo/util/bson_c' BSON = BSON_C @@ -31,6 +33,7 @@ module Mongo require 'mongo/util/support' require 'mongo/util/conversions' require 'mongo/util/server_version' +require 'mongo/util/bson_ruby' require 'mongo/errors' require 'mongo/constants' diff --git a/lib/mongo/collection.rb b/lib/mongo/collection.rb index ab46c0934d..cd498f34dc 100644 --- a/lib/mongo/collection.rb +++ b/lib/mongo/collection.rb @@ -216,7 +216,7 @@ def insert(doc_or_docs, options={}) def remove(selector={}) message = ByteBuffer.new message.put_int(0) - BSON.serialize_cstr(message, "#{@db.name}.#{@name}") + BSON_RUBY.serialize_cstr(message, "#{@db.name}.#{@name}") message.put_int(0) message.put_array(BSON_SERIALIZER.serialize(selector, false).unpack("C*")) @connection.send_message(Mongo::Constants::OP_DELETE, message, @@ -243,7 +243,7 @@ def remove(selector={}) def update(selector, document, options={}) message = ByteBuffer.new message.put_int(0) - BSON.serialize_cstr(message, "#{@db.name}.#{@name}") + BSON_RUBY.serialize_cstr(message, "#{@db.name}.#{@name}") update_options = 0 update_options += 1 if options[:upsert] update_options += 2 if options[:multi] @@ -507,7 +507,7 @@ def normalize_hint_fields(hint) def insert_documents(documents, collection_name=@name, check_keys=true, safe=false) message = ByteBuffer.new message.put_int(0) - BSON.serialize_cstr(message, "#{@db.name}.#{collection_name}") + BSON_RUBY.serialize_cstr(message, "#{@db.name}.#{collection_name}") documents.each { |doc| message.put_array(BSON_SERIALIZER.serialize(doc, check_keys).unpack("C*")) } if safe @connection.send_message_with_safe_check(Mongo::Constants::OP_INSERT, message, @db.name, diff --git a/lib/mongo/connection.rb b/lib/mongo/connection.rb index 17fbe6ee78..32f23a930c 100644 --- a/lib/mongo/connection.rb +++ b/lib/mongo/connection.rb @@ -467,7 +467,7 @@ def read_documents(number_received, cursor_id, sock) def last_error_message(db_name) message = ByteBuffer.new message.put_int(0) - BSON.serialize_cstr(message, "#{db_name}.$cmd") + BSON_RUBY.serialize_cstr(message, "#{db_name}.$cmd") message.put_int(0) message.put_int(-1) message.put_array(BSON_SERIALIZER.serialize({:getlasterror => 1}, false).unpack("C*")) diff --git a/lib/mongo/cursor.rb b/lib/mongo/cursor.rb index bdf916acca..6284331f9b 100644 --- a/lib/mongo/cursor.rb +++ b/lib/mongo/cursor.rb @@ -286,7 +286,7 @@ def refill_via_get_more # DB name. db_name = @admin ? 'admin' : @db.name - BSON.serialize_cstr(message, "#{db_name}.#{@collection.name}") + BSON_RUBY.serialize_cstr(message, "#{db_name}.#{@collection.name}") # Number of results to return; db decides for now. message.put_int(0) @@ -317,7 +317,7 @@ def construct_query_message message = ByteBuffer.new message.put_int(query_opts) db_name = @admin ? 'admin' : @db.name - BSON.serialize_cstr(message, "#{db_name}.#{@collection.name}") + BSON_RUBY.serialize_cstr(message, "#{db_name}.#{@collection.name}") message.put_int(@skip) message.put_int(@limit) selector = @selector diff --git a/lib/mongo/util/bson_c.rb b/lib/mongo/util/bson_c.rb index 4c3d640cb6..d6b349a016 100644 --- a/lib/mongo/util/bson_c.rb +++ b/lib/mongo/util/bson_c.rb @@ -1,25 +1,6 @@ # A thin wrapper for the CBson class class BSON_C - if RUBY_VERSION >= '1.9' - def self.to_utf8(str) - str.encode("utf-8") - end - else - def self.to_utf8(str) - begin - str.unpack("U*") - rescue => ex - raise InvalidStringEncoding, "String not valid utf-8: #{str}" - end - str - end - end - - def self.serialize_cstr(buf, val) - buf.put_array(to_utf8(val.to_s).unpack("C*") + [0]) - end - def self.serialize(obj, check_keys=false) ByteBuffer.new(CBson.serialize(obj, check_keys)) end @@ -34,12 +15,4 @@ def self.deserialize(buf=nil) CBson.deserialize(buf.to_s) end - def deserialize(buf=nil) - self.class.deserialize(buf) - end - - def serialize(buf, check_keys=false) - self.class.serialize(buf, check_keys) - end - end diff --git a/lib/mongo/util/bson_ruby.rb b/lib/mongo/util/bson_ruby.rb index 6c1f5d4e98..078de1591f 100644 --- a/lib/mongo/util/bson_ruby.rb +++ b/lib/mongo/util/bson_ruby.rb @@ -69,7 +69,7 @@ def self.to_utf8(str) end def self.serialize_cstr(buf, val) - buf.put_array(to_utf8(val.to_s).unpack("C*") + [0]) + buf.put_array(to_utf8(val.to_s).unpack("C*") << 0) end def to_a diff --git a/test/test_bson.rb b/test/test_bson.rb index c243322d31..964a102146 100644 --- a/test/test_bson.rb +++ b/test/test_bson.rb @@ -1,35 +1,31 @@ +# coding:utf-8 require 'test/test_helper' -require 'iconv' class BSONTest < Test::Unit::TestCase include Mongo - def setup - # We don't pass a DB to the constructor, even though we are about to test - # deserialization. This means that when we deserialize, any DBRefs will - # have nil @db ivars. That's fine for now. - #BSON = BSON.new - end - def test_string doc = {'doc' => 'hello, world'} bson = bson = BSON.serialize(doc) assert_equal doc, BSON.deserialize(bson) end - def test_valid_utf8_string - doc = {'doc' => "aéあ"} + doc = {'doc' => "aé"} bson = bson = BSON.serialize(doc) assert_equal doc, BSON.deserialize(bson) end - def test_invalid_string - string = Iconv.conv('iso-8859-1', 'utf-8', 'aé').first - doc = {'doc' => string} - assert_raise InvalidStringEncoding do - BSON.serialize(doc) + # We'll raise this exception only in 1.8 since 1.9 forces UTF-8 conversion. + if RUBY_VERSION < '1.9' + require 'iconv' + def test_invalid_string + string = Iconv.conv('iso-8859-1', 'utf-8', 'aé').first + doc = {'doc' => string} + assert_raise InvalidStringEncoding do + BSON.serialize(doc) + end end end