mongodb-mongo 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +216 -0
- data/Rakefile +54 -0
- data/bin/mongo_console +21 -0
- data/bin/validate +51 -0
- data/examples/benchmarks.rb +38 -0
- data/examples/blog.rb +76 -0
- data/examples/index_test.rb +128 -0
- data/examples/simple.rb +17 -0
- data/lib/mongo/admin.rb +86 -0
- data/lib/mongo/collection.rb +161 -0
- data/lib/mongo/cursor.rb +230 -0
- data/lib/mongo/db.rb +399 -0
- data/lib/mongo/message/get_more_message.rb +21 -0
- data/lib/mongo/message/insert_message.rb +19 -0
- data/lib/mongo/message/kill_cursors_message.rb +20 -0
- data/lib/mongo/message/message.rb +68 -0
- data/lib/mongo/message/message_header.rb +34 -0
- data/lib/mongo/message/msg_message.rb +17 -0
- data/lib/mongo/message/opcodes.rb +16 -0
- data/lib/mongo/message/query_message.rb +67 -0
- data/lib/mongo/message/remove_message.rb +20 -0
- data/lib/mongo/message/update_message.rb +21 -0
- data/lib/mongo/message.rb +4 -0
- data/lib/mongo/mongo.rb +98 -0
- data/lib/mongo/query.rb +110 -0
- data/lib/mongo/types/binary.rb +34 -0
- data/lib/mongo/types/dbref.rb +37 -0
- data/lib/mongo/types/objectid.rb +137 -0
- data/lib/mongo/types/regexp_of_holding.rb +44 -0
- data/lib/mongo/types/undefined.rb +31 -0
- data/lib/mongo/util/bson.rb +431 -0
- data/lib/mongo/util/byte_buffer.rb +163 -0
- data/lib/mongo/util/ordered_hash.rb +68 -0
- data/lib/mongo/util/xml_to_ruby.rb +102 -0
- data/lib/mongo.rb +12 -0
- data/mongo-ruby-driver.gemspec +62 -0
- data/tests/test_admin.rb +60 -0
- data/tests/test_bson.rb +135 -0
- data/tests/test_byte_buffer.rb +69 -0
- data/tests/test_cursor.rb +66 -0
- data/tests/test_db.rb +85 -0
- data/tests/test_db_api.rb +354 -0
- data/tests/test_db_connection.rb +17 -0
- data/tests/test_message.rb +35 -0
- data/tests/test_objectid.rb +98 -0
- data/tests/test_ordered_hash.rb +85 -0
- data/tests/test_round_trip.rb +116 -0
- metadata +100 -0
@@ -0,0 +1,354 @@
|
|
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 DBAPITest < Test::Unit::TestCase
|
7
|
+
|
8
|
+
include XGen::Mongo::Driver
|
9
|
+
|
10
|
+
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
|
+
@coll = @db.collection('test')
|
15
|
+
@coll.clear
|
16
|
+
@r1 = @coll.insert('a' => 1) # collection not created until it's used
|
17
|
+
@coll_full_name = 'ruby-mongo-test.test'
|
18
|
+
end
|
19
|
+
|
20
|
+
def teardown
|
21
|
+
if @db.connected?
|
22
|
+
@coll.clear unless @coll == nil
|
23
|
+
@db.close
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_clear
|
28
|
+
assert_equal 1, @coll.count
|
29
|
+
@coll.clear
|
30
|
+
assert_equal 0, @coll.count
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_insert
|
34
|
+
@coll.insert('a' => 2)
|
35
|
+
@coll.insert('b' => 3)
|
36
|
+
|
37
|
+
assert_equal 3, @coll.count
|
38
|
+
docs = @coll.find().to_a
|
39
|
+
assert_equal 3, docs.length
|
40
|
+
assert docs.detect { |row| row['a'] == 1 }
|
41
|
+
assert docs.detect { |row| row['a'] == 2 }
|
42
|
+
assert docs.detect { |row| row['b'] == 3 }
|
43
|
+
|
44
|
+
@coll << {'b' => 4}
|
45
|
+
docs = @coll.find().to_a
|
46
|
+
assert_equal 4, docs.length
|
47
|
+
assert docs.detect { |row| row['b'] == 4 }
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_find_simple
|
51
|
+
@r2 = @coll.insert('a' => 2)
|
52
|
+
@r3 = @coll.insert('b' => 3)
|
53
|
+
# Check sizes
|
54
|
+
docs = @coll.find().to_a
|
55
|
+
assert_equal 3, docs.size
|
56
|
+
assert_equal 3, @coll.count
|
57
|
+
|
58
|
+
# Find by other value
|
59
|
+
docs = @coll.find('a' => @r1['a']).to_a
|
60
|
+
assert_equal 1, docs.size
|
61
|
+
doc = docs.first
|
62
|
+
assert_equal doc['_id'], @r1['_id']
|
63
|
+
assert_equal doc['a'], @r1['a']
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_find_advanced
|
67
|
+
@coll.insert('a' => 2)
|
68
|
+
@coll.insert('b' => 3)
|
69
|
+
|
70
|
+
# Find by advanced query (less than)
|
71
|
+
docs = @coll.find('a' => { '$lt' => 10 }).to_a
|
72
|
+
assert_equal 2, docs.size
|
73
|
+
assert docs.detect { |row| row['a'] == 1 }
|
74
|
+
assert docs.detect { |row| row['a'] == 2 }
|
75
|
+
|
76
|
+
# Find by advanced query (greater than)
|
77
|
+
docs = @coll.find('a' => { '$gt' => 1 }).to_a
|
78
|
+
assert_equal 1, docs.size
|
79
|
+
assert docs.detect { |row| row['a'] == 2 }
|
80
|
+
|
81
|
+
# Find by advanced query (less than or equal to)
|
82
|
+
docs = @coll.find('a' => { '$lte' => 1 }).to_a
|
83
|
+
assert_equal 1, docs.size
|
84
|
+
assert docs.detect { |row| row['a'] == 1 }
|
85
|
+
|
86
|
+
# Find by advanced query (greater than or equal to)
|
87
|
+
docs = @coll.find('a' => { '$gte' => 1 }).to_a
|
88
|
+
assert_equal 2, docs.size
|
89
|
+
assert docs.detect { |row| row['a'] == 1 }
|
90
|
+
assert docs.detect { |row| row['a'] == 2 }
|
91
|
+
|
92
|
+
# Find by advanced query (between)
|
93
|
+
docs = @coll.find('a' => { '$gt' => 1, '$lt' => 3 }).to_a
|
94
|
+
assert_equal 1, docs.size
|
95
|
+
assert docs.detect { |row| row['a'] == 2 }
|
96
|
+
|
97
|
+
# Find by advanced query (in clause)
|
98
|
+
docs = @coll.find('a' => {'$in' => [1,2]}).to_a
|
99
|
+
assert_equal 2, docs.size
|
100
|
+
assert docs.detect { |row| row['a'] == 1 }
|
101
|
+
assert docs.detect { |row| row['a'] == 2 }
|
102
|
+
|
103
|
+
# Find by advanced query (regexp)
|
104
|
+
docs = @coll.find('a' => /[1|2]/).to_a
|
105
|
+
assert_equal 2, docs.size
|
106
|
+
assert docs.detect { |row| row['a'] == 1 }
|
107
|
+
assert docs.detect { |row| row['a'] == 2 }
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_find_sorting
|
111
|
+
@coll.clear
|
112
|
+
@coll.insert('a' => 1, 'b' => 2)
|
113
|
+
@coll.insert('a' => 2, 'b' => 1)
|
114
|
+
@coll.insert('a' => 3, 'b' => 2)
|
115
|
+
@coll.insert('a' => 4, 'b' => 1)
|
116
|
+
|
117
|
+
# Sorting (ascending)
|
118
|
+
docs = @coll.find({'a' => { '$lt' => 10 }}, :sort => {'a' => 1}).to_a
|
119
|
+
assert_equal 4, docs.size
|
120
|
+
assert_equal 1, docs[0]['a']
|
121
|
+
assert_equal 2, docs[1]['a']
|
122
|
+
assert_equal 3, docs[2]['a']
|
123
|
+
assert_equal 4, docs[3]['a']
|
124
|
+
|
125
|
+
# Sorting (descending)
|
126
|
+
docs = @coll.find({'a' => { '$lt' => 10 }}, :sort => {'a' => -1}).to_a
|
127
|
+
assert_equal 4, docs.size
|
128
|
+
assert_equal 4, docs[0]['a']
|
129
|
+
assert_equal 3, docs[1]['a']
|
130
|
+
assert_equal 2, docs[2]['a']
|
131
|
+
assert_equal 1, docs[3]['a']
|
132
|
+
|
133
|
+
# Sorting using array of names; assumes ascending order.
|
134
|
+
docs = @coll.find({'a' => { '$lt' => 10 }}, :sort => ['a']).to_a
|
135
|
+
assert_equal 4, docs.size
|
136
|
+
assert_equal 1, docs[0]['a']
|
137
|
+
assert_equal 2, docs[1]['a']
|
138
|
+
assert_equal 3, docs[2]['a']
|
139
|
+
assert_equal 4, docs[3]['a']
|
140
|
+
|
141
|
+
# Sorting using single name; assumes ascending order.
|
142
|
+
docs = @coll.find({'a' => { '$lt' => 10 }}, :sort => 'a').to_a
|
143
|
+
assert_equal 4, docs.size
|
144
|
+
assert_equal 1, docs[0]['a']
|
145
|
+
assert_equal 2, docs[1]['a']
|
146
|
+
assert_equal 3, docs[2]['a']
|
147
|
+
assert_equal 4, docs[3]['a']
|
148
|
+
|
149
|
+
docs = @coll.find({'a' => { '$lt' => 10 }}, :sort => ['b', 'a']).to_a
|
150
|
+
assert_equal 4, docs.size
|
151
|
+
assert_equal 2, docs[0]['a']
|
152
|
+
assert_equal 4, docs[1]['a']
|
153
|
+
assert_equal 1, docs[2]['a']
|
154
|
+
assert_equal 3, docs[3]['a']
|
155
|
+
|
156
|
+
# Sorting using empty array; no order guarantee (Mongo bug #898) but
|
157
|
+
# should not blow up.
|
158
|
+
docs = @coll.find({'a' => { '$lt' => 10 }}, :sort => []).to_a
|
159
|
+
assert_equal 4, docs.size
|
160
|
+
|
161
|
+
# Sorting using array of hashes; no order guarantee (Mongo bug #898) but
|
162
|
+
# should not blow up.
|
163
|
+
docs = @coll.find({'a' => { '$lt' => 10 }}, :sort => [{'b' => 1}, {'a' => -1}]).to_a
|
164
|
+
assert_equal 4, docs.size
|
165
|
+
|
166
|
+
# Sorting using ordered hash. You can use an unordered one, but then the
|
167
|
+
# order of the keys won't be guaranteed thus your sort won't make sense.
|
168
|
+
oh = OrderedHash.new
|
169
|
+
oh['a'] = -1
|
170
|
+
docs = @coll.find({'a' => { '$lt' => 10 }}, :sort => oh).to_a
|
171
|
+
assert_equal 4, docs.size
|
172
|
+
assert_equal 4, docs[0]['a']
|
173
|
+
assert_equal 3, docs[1]['a']
|
174
|
+
assert_equal 2, docs[2]['a']
|
175
|
+
assert_equal 1, docs[3]['a']
|
176
|
+
|
177
|
+
# TODO this will not pass due to known Mongo bug #898
|
178
|
+
# oh = OrderedHash.new
|
179
|
+
# oh['b'] = -1
|
180
|
+
# oh['a'] = 1
|
181
|
+
# docs = @coll.find({'a' => { '$lt' => 10 }}, :sort => oh).to_a
|
182
|
+
# assert_equal 4, docs.size
|
183
|
+
# assert_equal 1, docs[0]['a']
|
184
|
+
# assert_equal 3, docs[1]['a']
|
185
|
+
# assert_equal 2, docs[2]['a']
|
186
|
+
# assert_equal 4, docs[3]['a']
|
187
|
+
end
|
188
|
+
|
189
|
+
def test_find_limits
|
190
|
+
@coll.insert('b' => 2)
|
191
|
+
@coll.insert('c' => 3)
|
192
|
+
@coll.insert('d' => 4)
|
193
|
+
|
194
|
+
docs = @coll.find({}, :limit => 1).to_a
|
195
|
+
assert_equal 1, docs.size
|
196
|
+
docs = @coll.find({}, :limit => 2).to_a
|
197
|
+
assert_equal 2, docs.size
|
198
|
+
docs = @coll.find({}, :limit => 3).to_a
|
199
|
+
assert_equal 3, docs.size
|
200
|
+
docs = @coll.find({}, :limit => 4).to_a
|
201
|
+
assert_equal 4, docs.size
|
202
|
+
docs = @coll.find({}).to_a
|
203
|
+
assert_equal 4, docs.size
|
204
|
+
docs = @coll.find({}, :limit => 99).to_a
|
205
|
+
assert_equal 4, docs.size
|
206
|
+
end
|
207
|
+
|
208
|
+
def test_drop_collection
|
209
|
+
assert @db.drop_collection(@coll.name), "drop of collection #{@coll.name} failed"
|
210
|
+
assert !@db.collection_names.include?(@coll_full_name)
|
211
|
+
@coll = nil
|
212
|
+
end
|
213
|
+
|
214
|
+
def test_collection_names
|
215
|
+
names = @db.collection_names
|
216
|
+
assert names.length >= 1
|
217
|
+
assert names.include?(@coll_full_name)
|
218
|
+
|
219
|
+
coll2 = @db.collection('test2')
|
220
|
+
coll2.insert('a' => 1) # collection not created until it's used
|
221
|
+
names = @db.collection_names
|
222
|
+
assert names.length >= 2
|
223
|
+
assert names.include?(@coll_full_name)
|
224
|
+
assert names.include?('ruby-mongo-test.test2')
|
225
|
+
ensure
|
226
|
+
@db.drop_collection('test2')
|
227
|
+
end
|
228
|
+
|
229
|
+
def test_collections_info
|
230
|
+
cursor = @db.collections_info
|
231
|
+
rows = cursor.to_a
|
232
|
+
assert rows.length >= 1
|
233
|
+
row = rows.detect { |r| r['name'] == @coll_full_name }
|
234
|
+
assert_not_nil row
|
235
|
+
end
|
236
|
+
|
237
|
+
def test_collection_options
|
238
|
+
@db.drop_collection('foobar')
|
239
|
+
@db.strict = true
|
240
|
+
|
241
|
+
begin
|
242
|
+
coll = @db.create_collection('foobar', :capped => true, :size => 1024)
|
243
|
+
options = coll.options()
|
244
|
+
assert_equal 'foobar', options['create']
|
245
|
+
assert_equal true, options['capped']
|
246
|
+
assert_equal 1024, options['size']
|
247
|
+
rescue => ex
|
248
|
+
@db.drop_collection('foobar')
|
249
|
+
fail "did not expect exception \"#{ex}\""
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
def test_index_information
|
254
|
+
@db.create_index(@coll.name, 'index_name', ['a'])
|
255
|
+
list = @db.index_information(@coll.name)
|
256
|
+
assert_equal 1, list.length
|
257
|
+
|
258
|
+
info = list[0]
|
259
|
+
assert_equal 'index_name', info[:name]
|
260
|
+
assert_equal 1, info[:keys]['a']
|
261
|
+
end
|
262
|
+
|
263
|
+
def test_array
|
264
|
+
@coll << {'b' => [1, 2, 3]}
|
265
|
+
rows = @coll.find({}, {:fields => ['b']}).to_a
|
266
|
+
assert_equal 1, rows.length
|
267
|
+
assert_equal [1, 2, 3], rows[0]['b']
|
268
|
+
end
|
269
|
+
|
270
|
+
def test_regex
|
271
|
+
regex = /foobar/i
|
272
|
+
@coll << {'b' => regex}
|
273
|
+
rows = @coll.find({}, {:fields => ['b']}).to_a
|
274
|
+
assert_equal 1, rows.length
|
275
|
+
assert_equal regex, rows[0]['b']
|
276
|
+
end
|
277
|
+
|
278
|
+
def test_strict
|
279
|
+
assert !@db.strict?
|
280
|
+
@db.strict = true
|
281
|
+
assert @db.strict?
|
282
|
+
end
|
283
|
+
|
284
|
+
def test_strict_access_collection
|
285
|
+
@db.strict = true
|
286
|
+
begin
|
287
|
+
@db.collection('does-not-exist')
|
288
|
+
fail "expected exception"
|
289
|
+
rescue => ex
|
290
|
+
assert_equal "Collection does-not-exist doesn't exist. Currently in strict mode.", ex.to_s
|
291
|
+
ensure
|
292
|
+
@db.strict = false
|
293
|
+
@db.drop_collection('does-not-exist')
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
def test_strict_create_collection
|
298
|
+
@db.drop_collection('foobar')
|
299
|
+
@db.strict = true
|
300
|
+
|
301
|
+
begin
|
302
|
+
@db.create_collection('foobar')
|
303
|
+
assert true
|
304
|
+
rescue => ex
|
305
|
+
fail "did not expect exception \"#{ex}\""
|
306
|
+
end
|
307
|
+
|
308
|
+
# Now the collection exists. This time we should see an exception.
|
309
|
+
begin
|
310
|
+
@db.create_collection('foobar')
|
311
|
+
fail "expected exception"
|
312
|
+
rescue => ex
|
313
|
+
assert_equal "Collection foobar already exists. Currently in strict mode.", ex.to_s
|
314
|
+
ensure
|
315
|
+
@db.strict = false
|
316
|
+
@db.drop_collection('foobar')
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
def test_to_a
|
321
|
+
cursor = @coll.find()
|
322
|
+
rows = cursor.to_a
|
323
|
+
|
324
|
+
# Make sure we get back exactly the same array the next time we ask
|
325
|
+
rows2 = cursor.to_a
|
326
|
+
assert_same rows, rows2
|
327
|
+
|
328
|
+
# Make sure we can still iterate after calling to_a
|
329
|
+
rows_with_each = cursor.collect{|row| row}
|
330
|
+
assert_equal rows, rows_with_each
|
331
|
+
|
332
|
+
# Make sure we can iterate more than once after calling to_a
|
333
|
+
end
|
334
|
+
|
335
|
+
def test_to_a_after_each
|
336
|
+
cursor = @coll.find
|
337
|
+
cursor.each { |row| row }
|
338
|
+
begin
|
339
|
+
cursor.to_a
|
340
|
+
fail "expected \"can't call\" error"
|
341
|
+
rescue => ex
|
342
|
+
assert_equal "can't call Cursor#to_a after calling Cursor#each", ex.to_s
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
def test_ismaster
|
347
|
+
assert @db.master?
|
348
|
+
end
|
349
|
+
|
350
|
+
def test_master
|
351
|
+
assert_equal "#{@db.host}:#{@db.port}", @db.master
|
352
|
+
end
|
353
|
+
|
354
|
+
end
|
@@ -0,0 +1,17 @@
|
|
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 DBConnectionTest < Test::Unit::TestCase
|
7
|
+
|
8
|
+
include XGen::Mongo::Driver
|
9
|
+
|
10
|
+
def test_no_exceptions
|
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-demo')
|
14
|
+
coll = db.collection('test')
|
15
|
+
coll.clear
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
$LOAD_PATH[0,0] = File.join(File.dirname(__FILE__), '..', 'lib')
|
2
|
+
require 'mongo'
|
3
|
+
require 'test/unit'
|
4
|
+
|
5
|
+
class MessageTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
include XGen::Mongo::Driver
|
8
|
+
|
9
|
+
def setup
|
10
|
+
@msg = Message.new(42)
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_initial_info
|
14
|
+
assert_equal Message::HEADER_SIZE, @msg.buf.length
|
15
|
+
@msg.write_long(1029)
|
16
|
+
@msg.buf.rewind
|
17
|
+
assert_equal Message::HEADER_SIZE + 8, @msg.buf.get_int
|
18
|
+
@msg.buf.get_int # skip message id
|
19
|
+
assert_equal 0, @msg.buf.get_int
|
20
|
+
assert_equal 42, @msg.buf.get_int
|
21
|
+
assert_equal 1029, @msg.buf.get_long
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_update_length
|
25
|
+
@msg.update_message_length
|
26
|
+
@msg.buf.rewind
|
27
|
+
assert_equal Message::HEADER_SIZE, @msg.buf.get_int
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_long_length
|
31
|
+
@msg.write_long(1027)
|
32
|
+
assert_equal Message::HEADER_SIZE + 8, @msg.buf.length
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
$LOAD_PATH[0,0] = File.join(File.dirname(__FILE__), '..', 'lib')
|
2
|
+
require 'mongo'
|
3
|
+
require 'test/unit'
|
4
|
+
|
5
|
+
class ObjectIDTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
include XGen::Mongo::Driver
|
8
|
+
|
9
|
+
def setup
|
10
|
+
@t = 42
|
11
|
+
@o = ObjectID.new(nil, @t)
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_index_for_time
|
15
|
+
t = 99
|
16
|
+
assert_equal 0, @o.index_for_time(t)
|
17
|
+
assert_equal 1, @o.index_for_time(t)
|
18
|
+
assert_equal 2, @o.index_for_time(t)
|
19
|
+
t = 100
|
20
|
+
assert_equal 0, @o.index_for_time(t)
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_time_bytes
|
24
|
+
a = @o.to_a
|
25
|
+
assert_equal @t, a[0]
|
26
|
+
3.times { |i| assert_equal 0, a[i+1] }
|
27
|
+
|
28
|
+
t = 43
|
29
|
+
o = ObjectID.new(nil, t)
|
30
|
+
a = o.to_a
|
31
|
+
assert_equal t, a[0]
|
32
|
+
3.times { |i| assert_equal 0, a[i+1] }
|
33
|
+
assert_equal 1, o.index_for_time(t) # 0 was used for o
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_different
|
37
|
+
o2 = ObjectID.new(nil, @t)
|
38
|
+
assert @o.to_a != o2.to_a
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_eql?
|
42
|
+
o2 = ObjectID.new(@o.to_a)
|
43
|
+
assert @o.eql?(o2)
|
44
|
+
assert @o == o2
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_to_s
|
48
|
+
s = @o.to_s
|
49
|
+
assert_equal 24, s.length
|
50
|
+
s =~ /^([0-9a-f]+)$/
|
51
|
+
assert_equal 24, $1.length
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_save_and_restore
|
55
|
+
host = ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost'
|
56
|
+
port = ENV['MONGO_RUBY_DRIVER_PORT'] || Mongo::DEFAULT_PORT
|
57
|
+
db = Mongo.new(host, port).db('ruby-mongo-test')
|
58
|
+
coll = db.collection('test')
|
59
|
+
|
60
|
+
coll.clear
|
61
|
+
coll << {'a' => 1, '_id' => @o}
|
62
|
+
|
63
|
+
row = coll.find().collect.first
|
64
|
+
assert_equal 1, row['a']
|
65
|
+
assert_equal @o, row['_id']
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_from_string
|
69
|
+
hex_str = @o.to_s
|
70
|
+
o2 = ObjectID.from_string(hex_str)
|
71
|
+
assert_equal hex_str, o2.to_s
|
72
|
+
assert_equal @o, o2
|
73
|
+
assert_equal @o.to_s, o2.to_s
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_legal_oid_string
|
77
|
+
assert !ObjectID.legal_oid_string(nil)
|
78
|
+
assert !ObjectID.legal_oid_string("fred")
|
79
|
+
assert !ObjectID.legal_oid_string("0000")
|
80
|
+
assert !ObjectID.legal_oid_string('000102030405060708090A0')
|
81
|
+
assert ObjectID.legal_oid_string('000102030405060708090A0B')
|
82
|
+
assert ObjectID.legal_oid_string('abcdefABCDEF123456789012')
|
83
|
+
assert !ObjectID.legal_oid_string('abcdefABCDEF12345678901x')
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_from_string_leading_zeroes
|
87
|
+
hex_str = '000000000000000000abcdef'
|
88
|
+
o = ObjectID.from_string(hex_str)
|
89
|
+
assert_equal hex_str, o.to_s
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_byte_order
|
93
|
+
hex_str = '000102030405060708090A0B'
|
94
|
+
o = ObjectID.from_string(hex_str)
|
95
|
+
assert_equal [0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x0b, 0x0a, 0x09, 0x08], o.to_a
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
$LOAD_PATH[0,0] = File.join(File.dirname(__FILE__), '..', 'lib')
|
2
|
+
require 'mongo/util/ordered_hash'
|
3
|
+
require 'test/unit'
|
4
|
+
|
5
|
+
class OrderedHashTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@oh = OrderedHash.new
|
9
|
+
@oh['c'] = 1
|
10
|
+
@oh['a'] = 2
|
11
|
+
@oh['z'] = 3
|
12
|
+
@ordered_keys = %w(c a z)
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_empty
|
16
|
+
assert_equal [], OrderedHash.new.keys
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_order_preserved
|
20
|
+
assert_equal @ordered_keys, @oh.keys
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_order_preserved_after_replace
|
24
|
+
@oh['a'] = 42
|
25
|
+
assert_equal @ordered_keys, @oh.keys
|
26
|
+
@oh['c'] = 'foobar'
|
27
|
+
assert_equal @ordered_keys, @oh.keys
|
28
|
+
@oh['z'] = /huh?/
|
29
|
+
assert_equal @ordered_keys, @oh.keys
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_each
|
33
|
+
keys = []
|
34
|
+
@oh.each { |k, v| keys << k }
|
35
|
+
assert_equal keys, @oh.keys
|
36
|
+
|
37
|
+
@oh['z'] = 42
|
38
|
+
assert_equal keys, @oh.keys
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_values
|
42
|
+
assert_equal [1, 2, 3], @oh.values
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_merge
|
46
|
+
other = OrderedHash.new
|
47
|
+
other['f'] = 'foo'
|
48
|
+
noob = @oh.merge(other)
|
49
|
+
assert_equal @ordered_keys + ['f'], noob.keys
|
50
|
+
assert_equal [1, 2, 3, 'foo'], noob.values
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_merge_bang
|
54
|
+
other = OrderedHash.new
|
55
|
+
other['f'] = 'foo'
|
56
|
+
@oh.merge!(other)
|
57
|
+
assert_equal @ordered_keys + ['f'], @oh.keys
|
58
|
+
assert_equal [1, 2, 3, 'foo'], @oh.values
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_merge_bang_with_overlap
|
62
|
+
other = OrderedHash.new
|
63
|
+
other['a'] = 'apple'
|
64
|
+
other['c'] = 'crab'
|
65
|
+
other['f'] = 'foo'
|
66
|
+
@oh.merge!(other)
|
67
|
+
assert_equal @ordered_keys + ['f'], @oh.keys
|
68
|
+
assert_equal ['crab', 'apple', 3, 'foo'], @oh.values
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_merge_bang_with_hash_with_overlap
|
72
|
+
other = Hash.new
|
73
|
+
other['a'] = 'apple'
|
74
|
+
other['c'] = 'crab'
|
75
|
+
other['f'] = 'foo'
|
76
|
+
@oh.merge!(other)
|
77
|
+
assert_equal @ordered_keys + ['f'], @oh.keys
|
78
|
+
assert_equal ['crab', 'apple', 3, 'foo'], @oh.values
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_inspect_retains_order
|
82
|
+
assert_equal '{"c"=>1, "a"=>2, "z"=>3}', @oh.inspect
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
HERE = File.dirname(__FILE__)
|
2
|
+
$LOAD_PATH[0,0] = File.join(HERE, '..', 'lib')
|
3
|
+
require 'mongo'
|
4
|
+
require 'mongo/util/xml_to_ruby'
|
5
|
+
require 'test/unit'
|
6
|
+
|
7
|
+
# For each xml/bson file in the data subdirectory, we turn the XML into an
|
8
|
+
# OrderedHash and then test both Ruby-to-BSON and BSON-to-Ruby translations.
|
9
|
+
#
|
10
|
+
# There is a whole other project that includes similar tests
|
11
|
+
# (http://github.com/mongodb/mongo-qa). If the directory ../mongo-qa exists,
|
12
|
+
# then we find the BSON test files there and use those, too. Use the Rake task
|
13
|
+
# "mongo_qa" to obtain those tests.
|
14
|
+
class RoundTripTest < Test::Unit::TestCase
|
15
|
+
|
16
|
+
include XGen::Mongo::Driver
|
17
|
+
|
18
|
+
@@ruby = nil
|
19
|
+
|
20
|
+
def setup
|
21
|
+
unless @@ruby
|
22
|
+
names = Dir[File.join(HERE, 'data', '*.xml')].collect {|f| File.basename(f).sub(/\.xml$/, '') }
|
23
|
+
@@ruby = {}
|
24
|
+
names.each { |name|
|
25
|
+
File.open(File.join(HERE, 'data', "#{name}.xml")) { |f|
|
26
|
+
@@ruby[name] = XMLToRuby.new.xml_to_ruby(f)
|
27
|
+
}
|
28
|
+
}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_dummy
|
33
|
+
assert true
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.create_test_for_round_trip_files_in_dir(dir)
|
37
|
+
names = Dir[File.join(dir, '*.xson')].collect {|f| File.basename(f).sub(/\.xson$/, '') }
|
38
|
+
names.each { |name|
|
39
|
+
eval <<EOS
|
40
|
+
def test_#{name}_#{dir.gsub(/[^a-zA-Z0-9_]/, '_')}
|
41
|
+
one_round_trip("#{dir}", "#{name}")
|
42
|
+
end
|
43
|
+
EOS
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
# Dynamically generate one test for each test file. This way, if one test
|
48
|
+
# fails the others will still run.
|
49
|
+
create_test_for_round_trip_files_in_dir(File.join(HERE, 'data'))
|
50
|
+
mongo_qa_dir = File.join(HERE, '..', 'mongo-qa/modules/bson_tests/tests')
|
51
|
+
if File.exist?(mongo_qa_dir)
|
52
|
+
%w(basic_types complex single_types).each { |subdir_name|
|
53
|
+
create_test_for_round_trip_files_in_dir(File.join(mongo_qa_dir, subdir_name))
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
# Round-trip comparisons of Ruby-to-BSON and back.
|
58
|
+
# * Take the objects that were read from XML
|
59
|
+
# * Turn them into BSON bytes
|
60
|
+
# * Compare that with the BSON files we have
|
61
|
+
# * Turn those BSON bytes back in to Ruby objects
|
62
|
+
# * Turn them back into BSON bytes
|
63
|
+
# * Compare that with the BSON files we have (or the bytes that were already
|
64
|
+
# generated)
|
65
|
+
def one_round_trip(dir, name)
|
66
|
+
obj = File.open(File.join(dir, "#{name}.xson")) { |f|
|
67
|
+
XMLToRuby.new.xml_to_ruby(f)
|
68
|
+
}
|
69
|
+
|
70
|
+
File.open(File.join(dir, "#{name}.bson"), 'r') { |f|
|
71
|
+
# Read the BSON from the file
|
72
|
+
bson = f.read
|
73
|
+
bson = if RUBY_VERSION >= '1.9'
|
74
|
+
bson.bytes.to_a
|
75
|
+
else
|
76
|
+
bson.split(//).collect { |c| c[0] }
|
77
|
+
end
|
78
|
+
|
79
|
+
# Turn the Ruby object into BSON bytes and compare with the BSON bytes
|
80
|
+
# from the file.
|
81
|
+
bson_from_ruby = BSON.new.serialize(obj).to_a
|
82
|
+
|
83
|
+
begin
|
84
|
+
assert_equal bson.length, bson_from_ruby.length
|
85
|
+
assert_equal bson, bson_from_ruby
|
86
|
+
rescue => ex
|
87
|
+
# File.open(File.join(dir, "#{name}_out_a.bson"), 'wb') { |f| # DEBUG
|
88
|
+
# bson_from_ruby.each { |b| f.putc(b) }
|
89
|
+
# }
|
90
|
+
raise ex
|
91
|
+
end
|
92
|
+
|
93
|
+
# Turn those BSON bytes back into a Ruby object.
|
94
|
+
#
|
95
|
+
# We're passing a nil db to the contructor here, but that's OK because
|
96
|
+
# the BSON DBFef bytes don't contain the db object in any case, and we
|
97
|
+
# don't care what the database is.
|
98
|
+
obj_from_bson = BSON.new(nil).deserialize(ByteBuffer.new(bson_from_ruby))
|
99
|
+
assert_kind_of OrderedHash, obj_from_bson
|
100
|
+
|
101
|
+
# Turn that Ruby object into BSON and compare it to the original BSON
|
102
|
+
# bytes.
|
103
|
+
bson_from_ruby = BSON.new.serialize(obj_from_bson).to_a
|
104
|
+
begin
|
105
|
+
assert_equal bson.length, bson_from_ruby.length
|
106
|
+
assert_equal bson, bson_from_ruby
|
107
|
+
rescue => ex
|
108
|
+
# File.open(File.join(dir, "#{name}_out_b.bson"), 'wb') { |f| # DEBUG
|
109
|
+
# bson_from_ruby.each { |b| f.putc(b) }
|
110
|
+
# }
|
111
|
+
raise ex
|
112
|
+
end
|
113
|
+
}
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|