animehunter-mongo 0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. data/README.rdoc +311 -0
  2. data/Rakefile +62 -0
  3. data/bin/bson_benchmark.rb +59 -0
  4. data/bin/mongo_console +21 -0
  5. data/bin/run_test_script +19 -0
  6. data/bin/standard_benchmark +109 -0
  7. data/examples/admin.rb +41 -0
  8. data/examples/benchmarks.rb +42 -0
  9. data/examples/blog.rb +76 -0
  10. data/examples/capped.rb +23 -0
  11. data/examples/cursor.rb +47 -0
  12. data/examples/gridfs.rb +87 -0
  13. data/examples/index_test.rb +125 -0
  14. data/examples/info.rb +30 -0
  15. data/examples/queries.rb +69 -0
  16. data/examples/simple.rb +23 -0
  17. data/examples/strict.rb +34 -0
  18. data/examples/types.rb +40 -0
  19. data/lib/mongo.rb +19 -0
  20. data/lib/mongo/admin.rb +87 -0
  21. data/lib/mongo/collection.rb +235 -0
  22. data/lib/mongo/cursor.rb +227 -0
  23. data/lib/mongo/db.rb +538 -0
  24. data/lib/mongo/gridfs.rb +16 -0
  25. data/lib/mongo/gridfs/chunk.rb +96 -0
  26. data/lib/mongo/gridfs/grid_store.rb +468 -0
  27. data/lib/mongo/message.rb +20 -0
  28. data/lib/mongo/message/get_more_message.rb +37 -0
  29. data/lib/mongo/message/insert_message.rb +35 -0
  30. data/lib/mongo/message/kill_cursors_message.rb +36 -0
  31. data/lib/mongo/message/message.rb +84 -0
  32. data/lib/mongo/message/message_header.rb +50 -0
  33. data/lib/mongo/message/msg_message.rb +33 -0
  34. data/lib/mongo/message/opcodes.rb +32 -0
  35. data/lib/mongo/message/query_message.rb +77 -0
  36. data/lib/mongo/message/remove_message.rb +36 -0
  37. data/lib/mongo/message/update_message.rb +37 -0
  38. data/lib/mongo/mongo.rb +164 -0
  39. data/lib/mongo/query.rb +119 -0
  40. data/lib/mongo/types/binary.rb +42 -0
  41. data/lib/mongo/types/code.rb +34 -0
  42. data/lib/mongo/types/dbref.rb +37 -0
  43. data/lib/mongo/types/objectid.rb +137 -0
  44. data/lib/mongo/types/regexp_of_holding.rb +44 -0
  45. data/lib/mongo/types/undefined.rb +31 -0
  46. data/lib/mongo/util/bson.rb +534 -0
  47. data/lib/mongo/util/byte_buffer.rb +167 -0
  48. data/lib/mongo/util/ordered_hash.rb +96 -0
  49. data/lib/mongo/util/xml_to_ruby.rb +107 -0
  50. data/mongo-ruby-driver.gemspec +99 -0
  51. data/tests/mongo-qa/_common.rb +8 -0
  52. data/tests/mongo-qa/admin +26 -0
  53. data/tests/mongo-qa/capped +22 -0
  54. data/tests/mongo-qa/count1 +18 -0
  55. data/tests/mongo-qa/dbs +22 -0
  56. data/tests/mongo-qa/find +10 -0
  57. data/tests/mongo-qa/find1 +15 -0
  58. data/tests/mongo-qa/gridfs_in +16 -0
  59. data/tests/mongo-qa/gridfs_out +17 -0
  60. data/tests/mongo-qa/indices +49 -0
  61. data/tests/mongo-qa/remove +25 -0
  62. data/tests/mongo-qa/stress1 +35 -0
  63. data/tests/mongo-qa/test1 +11 -0
  64. data/tests/mongo-qa/update +18 -0
  65. data/tests/test_admin.rb +69 -0
  66. data/tests/test_bson.rb +246 -0
  67. data/tests/test_byte_buffer.rb +69 -0
  68. data/tests/test_chunk.rb +84 -0
  69. data/tests/test_cursor.rb +121 -0
  70. data/tests/test_db.rb +160 -0
  71. data/tests/test_db_api.rb +701 -0
  72. data/tests/test_db_connection.rb +18 -0
  73. data/tests/test_grid_store.rb +284 -0
  74. data/tests/test_message.rb +35 -0
  75. data/tests/test_mongo.rb +78 -0
  76. data/tests/test_objectid.rb +98 -0
  77. data/tests/test_ordered_hash.rb +129 -0
  78. data/tests/test_round_trip.rb +116 -0
  79. metadata +133 -0
@@ -0,0 +1,8 @@
1
+ $LOAD_PATH[0,0] = File.join(File.dirname(__FILE__), '../..', 'lib')
2
+ require 'mongo'
3
+
4
+ DEFAULT_HOST = '127.0.0.1'
5
+ DEFAULT_PORT = 27017
6
+ DEFAULT_DB = 'driver_test_framework'
7
+
8
+ include XGen::Mongo::Driver
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.join(File.dirname(__FILE__), '_common.rb')
4
+ db = Mongo.new(DEFAULT_HOST, DEFAULT_PORT).db(DEFAULT_DB)
5
+
6
+ db.collection('test').insert({'test' => 1})
7
+ admin = db.admin
8
+
9
+ if $DEBUG
10
+ db.drop_collection('tester')
11
+ admin.profiling_level = :slow_only
12
+ end
13
+
14
+ ['test', 'pdlskwmf', '$'].each { |name|
15
+ begin
16
+ admin.validate_collection(name)
17
+ puts 'true'
18
+ rescue => ex
19
+ puts 'false'
20
+ end
21
+ }
22
+
23
+ level_xlation = {:off => 'off', :all => 'all', :slow_only => 'slowOnly'}
24
+ puts level_xlation[admin.profiling_level]
25
+ admin.profiling_level = :off
26
+ puts level_xlation[admin.profiling_level]
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.join(File.dirname(__FILE__), '_common.rb')
4
+ db = Mongo.new(DEFAULT_HOST, DEFAULT_PORT).db(DEFAULT_DB)
5
+
6
+ if $DEBUG
7
+ db.drop_collection('capped1')
8
+ db.drop_collection('capped2')
9
+ end
10
+
11
+ db.create_collection('capped1', :capped => true, :size => 500)
12
+ coll = db.collection('capped1')
13
+ coll.insert('x' => 1)
14
+ coll.insert('x' => 2)
15
+
16
+ db.create_collection('capped2', :capped => true, :size => 1000, :max => 11)
17
+ coll = db.collection('capped2')
18
+ str = ''
19
+ 100.times {
20
+ coll.insert('dashes' => str)
21
+ str << '-'
22
+ }
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.join(File.dirname(__FILE__), '_common.rb')
4
+ db = Mongo.new(DEFAULT_HOST, DEFAULT_PORT).db(DEFAULT_DB)
5
+
6
+ if $DEBUG
7
+ 3.times { |i| db.drop_collection("test#{i+1}") }
8
+ db.create_collection('test1')
9
+ db.collection('test2').insert({:name => 'a'})
10
+ c = db.collection('test3')
11
+ 100.times { |i| c.insert(:i => i, :foo => 'bar') }
12
+ end
13
+
14
+ puts db.collection('test1').count
15
+ puts db.collection('test2').count
16
+ puts db.collection('test3').count('i' => 'a')
17
+ puts db.collection('test3').count('i' => 3)
18
+ puts db.collection('test3').count({'i' => {'$gte' => 67}})
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.join(File.dirname(__FILE__), '_common.rb')
4
+ db = Mongo.new(DEFAULT_HOST, DEFAULT_PORT).db(DEFAULT_DB)
5
+
6
+ if $DEBUG
7
+ 3.times { |i| db.drop_collection("dbs_#{i+1}") }
8
+ end
9
+
10
+ def print_dbs_names(db)
11
+ db.collection_names.select{ |n| n =~ /\.dbs/ }.sort.each { |name|
12
+ puts name.sub(/^#{db.name}\./, '')
13
+ }
14
+ end
15
+
16
+ db.collection('dbs_1').insert('foo' => 'bar')
17
+ db.collection('dbs_2').insert('psi' => 'phi')
18
+ puts db.name
19
+ print_dbs_names(db)
20
+ db.drop_collection('dbs_1')
21
+ db.create_collection('dbs_3')
22
+ print_dbs_names(db)
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.join(File.dirname(__FILE__), '_common.rb')
4
+ db = Mongo.new(DEFAULT_HOST, DEFAULT_PORT).db(DEFAULT_DB)
5
+
6
+ if $DEBUG
7
+ db.drop_collection('test')
8
+ end
9
+
10
+ db.collection('test').insert('a' => 2)
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.join(File.dirname(__FILE__), '_common.rb')
4
+ db = Mongo.new(DEFAULT_HOST, DEFAULT_PORT).db(DEFAULT_DB)
5
+
6
+ if $DEBUG
7
+ db.drop_collection('c')
8
+ c = db.collection('c')
9
+ (5..15).each { |i| c.insert(:x => 0, :y => i, :z => (i+64).chr) }
10
+ (1..50).each { |i| c.insert(:x => 1, :y => i, :z => (i+64).chr) }
11
+ (5..15).each { |i| c.insert(:x => 2, :y => i, :z => (i+64).chr) }
12
+ end
13
+
14
+ cursor = db.collection('c').find({'x' => 1}, :sort => 'y', :offset => 20, :limit => 10)
15
+ cursor.each { |row| puts row['z'] }
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.join(File.dirname(__FILE__), '_common.rb')
4
+
5
+ require 'mongo/gridfs'
6
+ include XGen::Mongo::GridFS
7
+
8
+ db = Mongo.new(DEFAULT_HOST, DEFAULT_PORT).db(DEFAULT_DB)
9
+
10
+ input_file = ARGV[0]
11
+
12
+ File.open(input_file, "r") { |f|
13
+ GridStore.open(db, input_file, "w") { |g|
14
+ g.write(f.read)
15
+ }
16
+ }
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.join(File.dirname(__FILE__), '_common.rb')
4
+
5
+ require 'mongo/gridfs'
6
+ include XGen::Mongo::GridFS
7
+
8
+ db = Mongo.new(DEFAULT_HOST, DEFAULT_PORT).db(DEFAULT_DB)
9
+
10
+ input_file = ARGV[0]
11
+ output_file = ARGV[1]
12
+
13
+ File.open(output_file, "w") { |f|
14
+ GridStore.open(db, input_file, "r") { |g|
15
+ f.write(g.read)
16
+ }
17
+ }
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.join(File.dirname(__FILE__), '_common.rb')
4
+
5
+ include XGen::Mongo
6
+
7
+ db = Mongo.new(DEFAULT_HOST, DEFAULT_PORT).db(DEFAULT_DB)
8
+ x = db.collection('x')
9
+ y = db.collection('y')
10
+
11
+ def sorted_index_info(c)
12
+ c.index_information.sort { |a,b| a[:name] <=> b[:name] }
13
+ end
14
+
15
+ def sorted_info_keys(info)
16
+ info[:keys].keys.sort.collect { |key| "#{key}_1" }.join("_")
17
+ end
18
+
19
+ def check_keys(c, expected)
20
+ keys = sorted_index_info(c).collect {|info| sorted_info_keys(info)}
21
+ if keys == expected
22
+ ''
23
+ else
24
+ "#{c.name} indices should start out #{expected.inspect} but is #{keys.inspect}"
25
+ end
26
+ end
27
+
28
+ if $DEBUG
29
+ x.drop # also drops indexes
30
+ x.insert('field1' => 'f1', 'field2' => 'f2')
31
+ x.create_index('field1_1', 'field1')
32
+ x.create_index('field2_1', 'field2')
33
+ y.drop
34
+ end
35
+
36
+ # There should only be two indices on x, and none on y. We raise an error if
37
+ # the preconditions are not met. (They were not, on our testing harness, for a
38
+ # while due to Mongo behavior.)
39
+ err = []
40
+ err << check_keys(x, ['field1_1', 'field2_1'])
41
+ err << check_keys(y, [])
42
+ raise "\n#{err.join("\n")}" unless err == ['', '']
43
+
44
+ x.drop_index('field1_1')
45
+ sorted_index_info(x).each { |info| puts sorted_info_keys(info) }
46
+
47
+ y.create_index([['a', ASCENDING], ['b', ASCENDING], ['c', ASCENDING]])
48
+ y.create_index('d')
49
+ sorted_index_info(y).each { |info| puts sorted_info_keys(info) }
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.join(File.dirname(__FILE__), '_common.rb')
4
+ db = Mongo.new(DEFAULT_HOST, DEFAULT_PORT).db(DEFAULT_DB)
5
+
6
+ if $DEBUG
7
+ c = db.collection('remove1')
8
+ c.clear
9
+ 50.times { |i| c.insert(:a => i) }
10
+ c = db.collection('remove2')
11
+ c.clear
12
+ c.insert(:a => 3, :b => 1)
13
+ c.insert(:a => 3, :b => 3)
14
+ c.insert(:a => 2, :b => 3)
15
+ c.insert(:b => 3)
16
+ end
17
+
18
+ db.collection('remove1').clear
19
+ db.collection('remove2').remove('a' => 3)
20
+
21
+ if $DEBUG
22
+ puts "remove1 count = #{db.collection('remove1').count}"
23
+ puts "remove2 count = #{db.collection('remove2').count}"
24
+ db.collection('remove2').find.each { |row| puts row.inspect }
25
+ end
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ LONG_STRING = "lksjhasoh1298alshasoidiohaskjasiouashoasasiugoas" * 6
4
+
5
+ require File.join(File.dirname(__FILE__), '_common.rb')
6
+ db = Mongo.new(DEFAULT_HOST, DEFAULT_PORT).db(DEFAULT_DB)
7
+ c = db.collection('stress1')
8
+
9
+ n1 = 50_000
10
+ n2 = 10_000
11
+
12
+ if $DEBUG
13
+ n1 = 5
14
+ n2 = 1
15
+ c.drop
16
+ end
17
+
18
+ n1.times { |i|
19
+ c.insert(:name => "asdf#{i}", :date => Time.now, :id => i,
20
+ :blah => LONG_STRING, :subarray => [])
21
+ }
22
+ puts
23
+
24
+ n2.times { |i|
25
+ x = c.find_first({:id => i})
26
+ x['subarray'] = "foo#{i}"
27
+ p x
28
+ c.modify({:id => i}, x)
29
+ }
30
+ puts
31
+
32
+ if $DEBUG
33
+ puts "stress1 has #{c.count} records"
34
+ c.find.each { |row| puts "#{row['id']}: #{row['subarray'].inspect}" }
35
+ end
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.join(File.dirname(__FILE__), '_common.rb')
4
+ db = Mongo.new(DEFAULT_HOST, DEFAULT_PORT).db(DEFAULT_DB)
5
+ coll = db.collection('part1')
6
+
7
+ if $DEBUG
8
+ coll.drop
9
+ end
10
+
11
+ 100.times { |i| coll.insert('x' => i) }
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.join(File.dirname(__FILE__), '_common.rb')
4
+ db = Mongo.new(DEFAULT_HOST, DEFAULT_PORT).db(DEFAULT_DB)
5
+ foo = db.collection('foo')
6
+
7
+ if $DEBUG
8
+ foo.drop
9
+ foo.insert(:x => 1)
10
+ end
11
+
12
+ foo.modify({:x => 1}, {:x => 1, :y => 2})
13
+ foo.modify({:x => 2}, {:x => 1, :y => 7})
14
+ foo.repsert({:x => 3}, {:x => 4, :y => 1})
15
+
16
+ if $DEBUG
17
+ foo.find.each { |row| puts row.inspect }
18
+ end
@@ -0,0 +1,69 @@
1
+ $LOAD_PATH[0,0] = File.join(File.dirname(__FILE__), '..', 'lib')
2
+ require 'mongo'
3
+ require 'test/unit'
4
+
5
+ # NOTE: assumes Mongo is running
6
+ class AdminTest < Test::Unit::TestCase
7
+
8
+ include XGen::Mongo::Driver
9
+
10
+ @@db = Mongo.new(ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost',
11
+ ENV['MONGO_RUBY_DRIVER_PORT'] || Mongo::DEFAULT_PORT).db('ruby-mongo-test')
12
+ @@coll = @@db.collection('test')
13
+
14
+ def setup
15
+ # Insert some data to make sure the database itself exists.
16
+ @@coll.clear
17
+ @r1 = @@coll.insert('a' => 1) # collection not created until it's used
18
+ @@coll_full_name = 'ruby-mongo-test.test'
19
+ @admin = @@db.admin
20
+ end
21
+
22
+ def teardown
23
+ @admin.profiling_level = :off
24
+ @@coll.clear if @@coll
25
+ @@db.error
26
+ end
27
+
28
+ def test_default_profiling_level
29
+ assert_equal :off, @admin.profiling_level
30
+ end
31
+
32
+ def test_change_profiling_level
33
+ @admin.profiling_level = :slow_only
34
+ assert_equal :slow_only, @admin.profiling_level
35
+ @admin.profiling_level = :off
36
+ assert_equal :off, @admin.profiling_level
37
+ @admin.profiling_level = :all
38
+ assert_equal :all, @admin.profiling_level
39
+ begin
40
+ @admin.profiling_level = :medium
41
+ fail "shouldn't be able to do this"
42
+ rescue
43
+ end
44
+ end
45
+
46
+ def test_profiling_info
47
+ # Perform at least one query while profiling so we have something to see.
48
+ @admin.profiling_level = :all
49
+ @@coll.find()
50
+ @admin.profiling_level = :off
51
+
52
+ info = @admin.profiling_info
53
+ assert_kind_of Array, info
54
+ assert info.length >= 1
55
+ first = info.first
56
+ assert_kind_of String, first['info']
57
+ assert_kind_of Time, first['ts']
58
+ assert_kind_of Numeric, first['millis']
59
+ end
60
+
61
+ def test_validate_collection
62
+ doc = @admin.validate_collection(@@coll.name)
63
+ assert_not_nil doc
64
+ result = doc['result']
65
+ assert_not_nil result
66
+ assert_match /firstExtent/, result
67
+ end
68
+
69
+ end
@@ -0,0 +1,246 @@
1
+ $LOAD_PATH[0,0] = File.join(File.dirname(__FILE__), '..', 'lib')
2
+ require 'mongo'
3
+ require 'mongo/util/ordered_hash'
4
+ require 'test/unit'
5
+
6
+ class BSONTest < Test::Unit::TestCase
7
+
8
+ include XGen::Mongo::Driver
9
+
10
+ def setup
11
+ # We don't pass a DB to the constructor, even though we are about to test
12
+ # deserialization. This means that when we deserialize, any DBRefs will
13
+ # have nil @db ivars. That's fine for now.
14
+ @b = BSON.new
15
+ end
16
+
17
+ def test_string
18
+ doc = {'doc' => 'hello, world'}
19
+ @b.serialize(doc)
20
+ assert_equal doc, @b.deserialize
21
+ end
22
+
23
+ def test_code
24
+ doc = {'$where' => Code.new('this.a.b < this.b')}
25
+ @b.serialize(doc)
26
+ assert_equal doc, @b.deserialize
27
+ end
28
+
29
+ def test_number
30
+ doc = {'doc' => 41.99}
31
+ @b.serialize(doc)
32
+ assert_equal doc, @b.deserialize
33
+ end
34
+
35
+ def test_int
36
+ doc = {'doc' => 42}
37
+ @b.serialize(doc)
38
+ assert_equal doc, @b.deserialize
39
+
40
+ doc = {"doc" => -5600}
41
+ @b.serialize(doc)
42
+ assert_equal doc, @b.deserialize
43
+
44
+ doc = {"doc" => 2147483647}
45
+ @b.serialize(doc)
46
+ assert_equal doc, @b.deserialize
47
+
48
+ doc = {"doc" => -2147483648}
49
+ @b.serialize(doc)
50
+ assert_equal doc, @b.deserialize
51
+ end
52
+
53
+ def test_ordered_hash
54
+ doc = OrderedHash.new
55
+ doc["b"] = 1
56
+ doc["a"] = 2
57
+ doc["c"] = 3
58
+ doc["d"] = 4
59
+ @b.serialize(doc)
60
+ assert_equal doc, @b.deserialize
61
+ end
62
+
63
+ def test_object
64
+ doc = {'doc' => {'age' => 42, 'name' => 'Spongebob', 'shoe_size' => 9.5}}
65
+ @b.serialize(doc)
66
+ assert_equal doc, @b.deserialize
67
+ end
68
+
69
+ def test_oid
70
+ doc = {'doc' => ObjectID.new}
71
+ @b.serialize(doc)
72
+ assert_equal doc, @b.deserialize
73
+ end
74
+
75
+ def test_array
76
+ doc = {'doc' => [1, 2, 'a', 'b']}
77
+ @b.serialize(doc)
78
+ assert_equal doc, @b.deserialize
79
+ end
80
+
81
+ def test_regex
82
+ doc = {'doc' => /foobar/i}
83
+ @b.serialize(doc)
84
+ doc2 = @b.deserialize
85
+ assert_equal doc, doc2
86
+
87
+ r = doc2['doc']
88
+ assert_kind_of XGen::Mongo::Driver::RegexpOfHolding, r
89
+ assert_equal '', r.extra_options_str
90
+
91
+ r.extra_options_str << 'zywcab'
92
+ assert_equal 'zywcab', r.extra_options_str
93
+
94
+ b = BSON.new
95
+ doc = {'doc' => r}
96
+ b.serialize(doc)
97
+ doc2 = nil
98
+ doc2 = b.deserialize
99
+ assert_equal doc, doc2
100
+
101
+ r = doc2['doc']
102
+ assert_kind_of XGen::Mongo::Driver::RegexpOfHolding, r
103
+ assert_equal 'abcwyz', r.extra_options_str # must be sorted
104
+ end
105
+
106
+ def test_boolean
107
+ doc = {'doc' => true}
108
+ @b.serialize(doc)
109
+ assert_equal doc, @b.deserialize
110
+ end
111
+
112
+ def test_date
113
+ doc = {'date' => Time.now}
114
+ @b.serialize(doc)
115
+ doc2 = @b.deserialize
116
+ # Mongo only stores up to the millisecond
117
+ assert_in_delta doc['date'], doc2['date'], 0.001
118
+ end
119
+
120
+ def test_date_returns_as_utc
121
+ doc = {'date' => Time.now}
122
+ @b.serialize(doc)
123
+ doc2 = @b.deserialize
124
+ assert doc2['date'].utc?
125
+ end
126
+
127
+ def test_dbref
128
+ oid = ObjectID.new
129
+ doc = {}
130
+ doc['dbref'] = DBRef.new('namespace', oid)
131
+ @b.serialize(doc)
132
+ doc2 = @b.deserialize
133
+ assert_equal 'namespace', doc2['dbref'].namespace
134
+ assert_equal oid, doc2['dbref'].object_id
135
+ end
136
+
137
+ def test_symbol
138
+ doc = {'sym' => :foo}
139
+ @b.serialize(doc)
140
+ doc2 = @b.deserialize
141
+ assert_equal :foo, doc2['sym']
142
+ end
143
+
144
+ def test_binary
145
+ bin = Binary.new
146
+ 'binstring'.each_byte { |b| bin.put(b) }
147
+
148
+ doc = {'bin' => bin}
149
+ @b.serialize(doc)
150
+ doc2 = @b.deserialize
151
+ bin2 = doc2['bin']
152
+ assert_kind_of Binary, bin2
153
+ assert_equal 'binstring', bin2.to_s
154
+ assert_equal Binary::SUBTYPE_BYTES, bin2.subtype
155
+ end
156
+
157
+ def test_binary_type
158
+ bin = Binary.new([1, 2, 3, 4, 5], Binary::SUBTYPE_USER_DEFINED)
159
+
160
+ doc = {'bin' => bin}
161
+ @b.serialize(doc)
162
+ doc2 = @b.deserialize
163
+ bin2 = doc2['bin']
164
+ assert_kind_of Binary, bin2
165
+ assert_equal [1, 2, 3, 4, 5], bin2.to_a
166
+ assert_equal Binary::SUBTYPE_USER_DEFINED, bin2.subtype
167
+ end
168
+
169
+ def test_binary_byte_buffer
170
+ bb = ByteBuffer.new
171
+ 5.times { |i| bb.put(i + 1) }
172
+
173
+ doc = {'bin' => bb}
174
+ @b.serialize(doc)
175
+ doc2 = @b.deserialize
176
+ bin2 = doc2['bin']
177
+ assert_kind_of Binary, bin2
178
+ assert_equal [1, 2, 3, 4, 5], bin2.to_a
179
+ assert_equal Binary::SUBTYPE_BYTES, bin2.subtype
180
+ end
181
+
182
+ def test_undefined
183
+ doc = {'undef' => Undefined.new}
184
+ @b.serialize(doc)
185
+ doc2 = @b.deserialize
186
+ assert_kind_of Undefined, doc2['undef']
187
+ end
188
+
189
+ def test_put_id_first
190
+ val = OrderedHash.new
191
+ val['not_id'] = 1
192
+ val['_id'] = 2
193
+ roundtrip = @b.deserialize(@b.serialize(val).to_a)
194
+ assert_kind_of OrderedHash, roundtrip
195
+ assert_equal '_id', roundtrip.keys.first
196
+
197
+ val = {'a' => 'foo', 'b' => 'bar', :_id => 42, 'z' => 'hello'}
198
+ roundtrip = @b.deserialize(@b.serialize(val).to_a)
199
+ assert_kind_of OrderedHash, roundtrip
200
+ assert_equal '_id', roundtrip.keys.first
201
+ end
202
+
203
+ def test_nil_id
204
+ doc = {"_id" => nil}
205
+ assert_equal doc, @b.deserialize(@b.serialize(doc).to_a)
206
+ end
207
+
208
+ def test_timestamp
209
+ val = {"test" => [4, 20]}
210
+ assert_equal val, @b.deserialize([0x13, 0x00, 0x00, 0x00,
211
+ 0x11, 0x74, 0x65, 0x73,
212
+ 0x74, 0x00, 0x04, 0x00,
213
+ 0x00, 0x00, 0x14, 0x00,
214
+ 0x00, 0x00, 0x00])
215
+ end
216
+
217
+ def test_overflow
218
+ doc = {"x" => 2**45}
219
+ assert_raise RangeError do
220
+ @b.serialize(doc)
221
+ end
222
+
223
+ doc = {"x" => 2147483647}
224
+ assert_equal doc, @b.deserialize(@b.serialize(doc).to_a)
225
+
226
+ doc["x"] = doc["x"] + 1
227
+ assert_raise RangeError do
228
+ @b.serialize(doc)
229
+ end
230
+ end
231
+
232
+ def test_do_not_change_original_object
233
+ val = OrderedHash.new
234
+ val['not_id'] = 1
235
+ val['_id'] = 2
236
+ assert val.keys.include?('_id')
237
+ @b.serialize(val)
238
+ assert val.keys.include?('_id')
239
+
240
+ val = {'a' => 'foo', 'b' => 'bar', :_id => 42, 'z' => 'hello'}
241
+ assert val.keys.include?(:_id)
242
+ @b.serialize(val)
243
+ assert val.keys.include?(:_id)
244
+ end
245
+
246
+ end