mongo 0.1.0 → 0.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. data/README.rdoc +268 -71
  2. data/Rakefile +27 -62
  3. data/bin/bson_benchmark.rb +59 -0
  4. data/bin/mongo_console +3 -3
  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 +35 -0
  19. data/lib/mongo.rb +9 -2
  20. data/lib/mongo/admin.rb +65 -68
  21. data/lib/mongo/collection.rb +379 -117
  22. data/lib/mongo/connection.rb +151 -0
  23. data/lib/mongo/cursor.rb +271 -216
  24. data/lib/mongo/db.rb +500 -315
  25. data/lib/mongo/errors.rb +26 -0
  26. data/lib/mongo/gridfs.rb +16 -0
  27. data/lib/mongo/gridfs/chunk.rb +92 -0
  28. data/lib/mongo/gridfs/grid_store.rb +464 -0
  29. data/lib/mongo/message.rb +16 -0
  30. data/lib/mongo/message/get_more_message.rb +24 -13
  31. data/lib/mongo/message/insert_message.rb +29 -11
  32. data/lib/mongo/message/kill_cursors_message.rb +23 -12
  33. data/lib/mongo/message/message.rb +74 -62
  34. data/lib/mongo/message/message_header.rb +35 -24
  35. data/lib/mongo/message/msg_message.rb +21 -9
  36. data/lib/mongo/message/opcodes.rb +26 -15
  37. data/lib/mongo/message/query_message.rb +63 -43
  38. data/lib/mongo/message/remove_message.rb +29 -12
  39. data/lib/mongo/message/update_message.rb +30 -13
  40. data/lib/mongo/query.rb +97 -89
  41. data/lib/mongo/types/binary.rb +25 -21
  42. data/lib/mongo/types/code.rb +30 -0
  43. data/lib/mongo/types/dbref.rb +19 -23
  44. data/lib/mongo/types/objectid.rb +130 -116
  45. data/lib/mongo/types/regexp_of_holding.rb +27 -31
  46. data/lib/mongo/util/bson.rb +273 -160
  47. data/lib/mongo/util/byte_buffer.rb +32 -28
  48. data/lib/mongo/util/ordered_hash.rb +88 -42
  49. data/lib/mongo/util/xml_to_ruby.rb +18 -15
  50. data/mongo-ruby-driver.gemspec +103 -0
  51. data/test/mongo-qa/_common.rb +8 -0
  52. data/test/mongo-qa/admin +26 -0
  53. data/test/mongo-qa/capped +22 -0
  54. data/test/mongo-qa/count1 +18 -0
  55. data/test/mongo-qa/dbs +22 -0
  56. data/test/mongo-qa/find +10 -0
  57. data/test/mongo-qa/find1 +15 -0
  58. data/test/mongo-qa/gridfs_in +16 -0
  59. data/test/mongo-qa/gridfs_out +17 -0
  60. data/test/mongo-qa/indices +49 -0
  61. data/test/mongo-qa/remove +25 -0
  62. data/test/mongo-qa/stress1 +35 -0
  63. data/test/mongo-qa/test1 +11 -0
  64. data/test/mongo-qa/update +18 -0
  65. data/{tests → test}/test_admin.rb +25 -16
  66. data/test/test_bson.rb +268 -0
  67. data/{tests → test}/test_byte_buffer.rb +0 -0
  68. data/test/test_chunk.rb +84 -0
  69. data/test/test_collection.rb +282 -0
  70. data/test/test_connection.rb +101 -0
  71. data/test/test_cursor.rb +321 -0
  72. data/test/test_db.rb +196 -0
  73. data/test/test_db_api.rb +798 -0
  74. data/{tests → test}/test_db_connection.rb +4 -3
  75. data/test/test_grid_store.rb +284 -0
  76. data/{tests → test}/test_message.rb +1 -1
  77. data/test/test_objectid.rb +105 -0
  78. data/{tests → test}/test_ordered_hash.rb +55 -0
  79. data/{tests → test}/test_round_trip.rb +13 -9
  80. data/test/test_threading.rb +37 -0
  81. metadata +74 -32
  82. data/bin/validate +0 -51
  83. data/lib/mongo/mongo.rb +0 -74
  84. data/lib/mongo/types/undefined.rb +0 -31
  85. data/tests/test_bson.rb +0 -135
  86. data/tests/test_cursor.rb +0 -66
  87. data/tests/test_db.rb +0 -51
  88. data/tests/test_db_api.rb +0 -349
  89. data/tests/test_objectid.rb +0 -88
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.join(File.dirname(__FILE__), '_common.rb')
4
+ db = Connection.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 = Connection.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').find('i' => 'a').count
17
+ puts db.collection('test3').find('i' => 3).count
18
+ puts db.collection('test3').find({'i' => {'$gte' => 67}}).count
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.join(File.dirname(__FILE__), '_common.rb')
4
+ db = Connection.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 = Connection.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 = Connection.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', :skip => 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 GridFS
7
+
8
+ db = Connection.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 GridFS
7
+
8
+ db = Connection.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 Mongo
6
+
7
+ db = Connection.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 = Connection.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 = Connection.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_one({: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 = Connection.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 = Connection.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
@@ -5,26 +5,24 @@ require 'test/unit'
5
5
  # NOTE: assumes Mongo is running
6
6
  class AdminTest < Test::Unit::TestCase
7
7
 
8
- include XGen::Mongo::Driver
8
+ include Mongo
9
+
10
+ @@db = Connection.new(ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost',
11
+ ENV['MONGO_RUBY_DRIVER_PORT'] || Connection::DEFAULT_PORT).db('ruby-mongo-test')
12
+ @@coll = @@db.collection('test')
9
13
 
10
14
  def setup
11
- host = ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost'
12
- port = ENV['MONGO_RUBY_DRIVER_PORT'] || Mongo::DEFAULT_PORT
13
- @db = Mongo.new(host, port).db('ruby-mongo-test')
14
15
  # Insert some data to make sure the database itself exists.
15
- @coll = @db.collection('test')
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
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
20
  end
21
21
 
22
22
  def teardown
23
- if @db.connected?
24
- @admin.profiling_level = :off
25
- @coll.clear if @coll
26
- @db.close
27
- end
23
+ @admin.profiling_level = :off
24
+ @@coll.clear if @@coll
25
+ @@db.error
28
26
  end
29
27
 
30
28
  def test_default_profiling_level
@@ -36,12 +34,19 @@ class AdminTest < Test::Unit::TestCase
36
34
  assert_equal :slow_only, @admin.profiling_level
37
35
  @admin.profiling_level = :off
38
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
39
44
  end
40
45
 
41
46
  def test_profiling_info
42
47
  # Perform at least one query while profiling so we have something to see.
43
48
  @admin.profiling_level = :all
44
- @coll.find()
49
+ @@coll.find()
45
50
  @admin.profiling_level = :off
46
51
 
47
52
  info = @admin.profiling_info
@@ -54,7 +59,11 @@ class AdminTest < Test::Unit::TestCase
54
59
  end
55
60
 
56
61
  def test_validate_collection
57
- assert @admin.validate_collection(@coll.name)
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
58
67
  end
59
68
 
60
69
  end
@@ -0,0 +1,268 @@
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 Mongo
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 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 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_date_before_epoch
128
+ begin
129
+ doc = {'date' => Time.utc(1600)}
130
+ @b.serialize(doc)
131
+ doc2 = @b.deserialize
132
+ # Mongo only stores up to the millisecond
133
+ assert_in_delta doc['date'], doc2['date'], 0.001
134
+ rescue ArgumentError
135
+ # some versions of Ruby won't let you create pre-epoch Time instances
136
+ #
137
+ # TODO figure out how that will work if somebady has saved data
138
+ # w/ early dates already and is just querying for it.
139
+ end
140
+ end
141
+
142
+ def test_dbref
143
+ oid = ObjectID.new
144
+ doc = {}
145
+ doc['dbref'] = DBRef.new('namespace', oid)
146
+ @b.serialize(doc)
147
+ doc2 = @b.deserialize
148
+ assert_equal 'namespace', doc2['dbref'].namespace
149
+ assert_equal oid, doc2['dbref'].object_id
150
+ end
151
+
152
+ def test_symbol
153
+ doc = {'sym' => :foo}
154
+ @b.serialize(doc)
155
+ doc2 = @b.deserialize
156
+ assert_equal :foo, doc2['sym']
157
+ end
158
+
159
+ def test_binary
160
+ bin = Binary.new
161
+ 'binstring'.each_byte { |b| bin.put(b) }
162
+
163
+ doc = {'bin' => bin}
164
+ @b.serialize(doc)
165
+ doc2 = @b.deserialize
166
+ bin2 = doc2['bin']
167
+ assert_kind_of Binary, bin2
168
+ assert_equal 'binstring', bin2.to_s
169
+ assert_equal Binary::SUBTYPE_BYTES, bin2.subtype
170
+ end
171
+
172
+ def test_binary_type
173
+ bin = Binary.new([1, 2, 3, 4, 5], Binary::SUBTYPE_USER_DEFINED)
174
+
175
+ doc = {'bin' => bin}
176
+ @b.serialize(doc)
177
+ doc2 = @b.deserialize
178
+ bin2 = doc2['bin']
179
+ assert_kind_of Binary, bin2
180
+ assert_equal [1, 2, 3, 4, 5], bin2.to_a
181
+ assert_equal Binary::SUBTYPE_USER_DEFINED, bin2.subtype
182
+ end
183
+
184
+ def test_binary_byte_buffer
185
+ bb = ByteBuffer.new
186
+ 5.times { |i| bb.put(i + 1) }
187
+
188
+ doc = {'bin' => bb}
189
+ @b.serialize(doc)
190
+ doc2 = @b.deserialize
191
+ bin2 = doc2['bin']
192
+ assert_kind_of Binary, bin2
193
+ assert_equal [1, 2, 3, 4, 5], bin2.to_a
194
+ assert_equal Binary::SUBTYPE_BYTES, bin2.subtype
195
+ end
196
+
197
+ def test_put_id_first
198
+ val = OrderedHash.new
199
+ val['not_id'] = 1
200
+ val['_id'] = 2
201
+ roundtrip = @b.deserialize(@b.serialize(val).to_a)
202
+ assert_kind_of OrderedHash, roundtrip
203
+ assert_equal '_id', roundtrip.keys.first
204
+
205
+ val = {'a' => 'foo', 'b' => 'bar', :_id => 42, 'z' => 'hello'}
206
+ roundtrip = @b.deserialize(@b.serialize(val).to_a)
207
+ assert_kind_of OrderedHash, roundtrip
208
+ assert_equal '_id', roundtrip.keys.first
209
+ end
210
+
211
+ def test_nil_id
212
+ doc = {"_id" => nil}
213
+ assert_equal doc, @b.deserialize(@b.serialize(doc).to_a)
214
+ end
215
+
216
+ def test_timestamp
217
+ val = {"test" => [4, 20]}
218
+ assert_equal val, @b.deserialize([0x13, 0x00, 0x00, 0x00,
219
+ 0x11, 0x74, 0x65, 0x73,
220
+ 0x74, 0x00, 0x04, 0x00,
221
+ 0x00, 0x00, 0x14, 0x00,
222
+ 0x00, 0x00, 0x00])
223
+ end
224
+
225
+ def test_overflow
226
+ doc = {"x" => 2**75}
227
+ assert_raise RangeError do
228
+ @b.serialize(doc)
229
+ end
230
+
231
+ doc = {"x" => 9223372036854775}
232
+ assert_equal doc, @b.deserialize(@b.serialize(doc).to_a)
233
+
234
+ doc = {"x" => 9223372036854775807}
235
+ assert_equal doc, @b.deserialize(@b.serialize(doc).to_a)
236
+
237
+ doc["x"] = doc["x"] + 1
238
+ assert_raise RangeError do
239
+ @b.serialize(doc)
240
+ end
241
+
242
+ doc = {"x" => -9223372036854775}
243
+ assert_equal doc, @b.deserialize(@b.serialize(doc).to_a)
244
+
245
+ doc = {"x" => -9223372036854775808}
246
+ assert_equal doc, @b.deserialize(@b.serialize(doc).to_a)
247
+
248
+ doc["x"] = doc["x"] - 1
249
+ assert_raise RangeError do
250
+ @b.serialize(doc)
251
+ end
252
+ end
253
+
254
+ def test_do_not_change_original_object
255
+ val = OrderedHash.new
256
+ val['not_id'] = 1
257
+ val['_id'] = 2
258
+ assert val.keys.include?('_id')
259
+ @b.serialize(val)
260
+ assert val.keys.include?('_id')
261
+
262
+ val = {'a' => 'foo', 'b' => 'bar', :_id => 42, 'z' => 'hello'}
263
+ assert val.keys.include?(:_id)
264
+ @b.serialize(val)
265
+ assert val.keys.include?(:_id)
266
+ end
267
+
268
+ end