diff --git a/Rakefile b/Rakefile index e526d7c..c90e827 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 6f3d702..187f6e0 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 @@ require 'mongo/types/regexp_of_holding' 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 ab46c09..cd498f3 100644 --- a/lib/mongo/collection.rb +++ b/lib/mongo/collection.rb @@ -216,7 +216,7 @@ module Mongo 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 @@ module Mongo 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 @@ EOS 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 17fbe6e..32f23a9 100644 --- a/lib/mongo/connection.rb +++ b/lib/mongo/connection.rb @@ -467,7 +467,7 @@ module Mongo 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 bdf916a..6284331 100644 --- a/lib/mongo/cursor.rb +++ b/lib/mongo/cursor.rb @@ -286,7 +286,7 @@ module Mongo # 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 @@ module Mongo 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 4c3d640..d6b349a 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 @@ class BSON_C 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 6c1f5d4..078de15 100644 --- a/lib/mongo/util/bson_ruby.rb +++ b/lib/mongo/util/bson_ruby.rb @@ -69,7 +69,7 @@ class BSON_RUBY 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 c243322..964a102 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