mongo 1.0.9 → 1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ # encoding:utf-8
2
+ require './test/test_helper'
3
+
4
+ class BinaryTest < Test::Unit::TestCase
5
+ context "Inspecting" do
6
+ setup do
7
+ @data = ("THIS IS BINARY " * 50).unpack("c*")
8
+ end
9
+
10
+ should "not display actual data" do
11
+ binary = BSON::Binary.new(@data)
12
+ assert_equal "<BSON::Binary:#{binary.object_id}>", binary.inspect
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,528 @@
1
+ # encoding:utf-8
2
+ require './test/test_helper'
3
+ require 'complex'
4
+ require 'bigdecimal'
5
+ require 'rational'
6
+
7
+ begin
8
+ require 'active_support/core_ext'
9
+ Time.zone = "Pacific Time (US & Canada)"
10
+ Zone = Time.zone.now
11
+ rescue LoadError
12
+ warn 'Mocking time with zone'
13
+ module ActiveSupport
14
+ class TimeWithZone
15
+ end
16
+ end
17
+ Zone = ActiveSupport::TimeWithZone.new
18
+ end
19
+
20
+ class BSONTest < Test::Unit::TestCase
21
+
22
+ include BSON
23
+
24
+ # This setup allows us to change the decoders for
25
+ # cross-coder compatibility testing
26
+ def setup
27
+ @encoder = BSON::BSON_CODER
28
+ @decoder = @encoder
29
+ end
30
+
31
+ def assert_doc_pass(doc, options={})
32
+ bson = @encoder.serialize(doc)
33
+ if options[:debug]
34
+ puts "DEBUGGIN DOC:"
35
+ p bson.to_a
36
+ puts "DESERIALIZES TO:"
37
+ p @decoder.deserialize(bson)
38
+ end
39
+ assert_equal @decoder.serialize(doc).to_a, bson.to_a
40
+ assert_equal doc, @decoder.deserialize(bson)
41
+ end
42
+
43
+ def test_require_hash
44
+ assert_raise_error InvalidDocument, "takes a Hash" do
45
+ BSON.serialize('foo')
46
+ end
47
+
48
+ assert_raise_error InvalidDocument, "takes a Hash" do
49
+ BSON.serialize(Object.new)
50
+ end
51
+
52
+ assert_raise_error InvalidDocument, "takes a Hash" do
53
+ BSON.serialize(Set.new)
54
+ end
55
+ end
56
+
57
+ def test_string
58
+ doc = {'doc' => 'hello, world'}
59
+ assert_doc_pass(doc)
60
+ end
61
+
62
+ def test_valid_utf8_string
63
+ doc = {'doc' => 'aé'}
64
+ assert_doc_pass(doc)
65
+ end
66
+
67
+ def test_valid_utf8_key
68
+ doc = {'aé' => 'hello'}
69
+ assert_doc_pass(doc)
70
+ end
71
+
72
+ def test_document_length
73
+ doc = {'name' => 'a' * 5 * 1024 * 1024}
74
+ assert_raise InvalidDocument do
75
+ assert @encoder.serialize(doc)
76
+ end
77
+ end
78
+
79
+ # In 1.8 we test that other string encodings raise an exception.
80
+ # In 1.9 we test that they get auto-converted.
81
+ if RUBY_VERSION < '1.9'
82
+ require 'iconv'
83
+ def test_invalid_string
84
+ string = Iconv.conv('iso-8859-1', 'utf-8', 'aé')
85
+ doc = {'doc' => string}
86
+ assert_raise InvalidStringEncoding do
87
+ @encoder.serialize(doc)
88
+ end
89
+ end
90
+
91
+ def test_invalid_key
92
+ key = Iconv.conv('iso-8859-1', 'utf-8', 'aé')
93
+ doc = {key => 'hello'}
94
+ assert_raise InvalidStringEncoding do
95
+ @encoder.serialize(doc)
96
+ end
97
+ end
98
+ else
99
+ def test_non_utf8_string
100
+ bson = BSON::BSON_CODER.serialize({'str' => 'aé'.encode('iso-8859-1')})
101
+ result = BSON::BSON_CODER.deserialize(bson)['str']
102
+ assert_equal 'aé', result
103
+ assert_equal 'UTF-8', result.encoding.name
104
+ end
105
+
106
+ def test_non_utf8_key
107
+ bson = BSON::BSON_CODER.serialize({'aé'.encode('iso-8859-1') => 'hello'})
108
+ assert_equal 'hello', BSON::BSON_CODER.deserialize(bson)['aé']
109
+ end
110
+
111
+ # Based on a test from sqlite3-ruby
112
+ def test_default_internal_is_honored
113
+ before_enc = Encoding.default_internal
114
+
115
+ str = "壁に耳あり、障子に目あり"
116
+ bson = BSON::BSON_CODER.serialize("x" => str)
117
+
118
+ Encoding.default_internal = 'EUC-JP'
119
+ out = BSON::BSON_CODER.deserialize(bson)["x"]
120
+
121
+ assert_equal Encoding.default_internal, out.encoding
122
+ assert_equal str.encode('EUC-JP'), out
123
+ assert_equal str, out.encode(str.encoding)
124
+ ensure
125
+ Encoding.default_internal = before_enc
126
+ end
127
+ end
128
+
129
+ def test_code
130
+ doc = {'$where' => Code.new('this.a.b < this.b')}
131
+ assert_doc_pass(doc)
132
+ end
133
+
134
+ def test_code_with_scope
135
+ doc = {'$where' => Code.new('this.a.b < this.b', {'foo' => 1})}
136
+ assert_doc_pass(doc)
137
+ end
138
+
139
+ def test_double
140
+ doc = {'doc' => 41.25}
141
+ assert_doc_pass(doc)
142
+ end
143
+
144
+ def test_int
145
+ doc = {'doc' => 42}
146
+ assert_doc_pass(doc)
147
+
148
+ doc = {"doc" => -5600}
149
+ assert_doc_pass(doc)
150
+
151
+ doc = {"doc" => 2147483647}
152
+ assert_doc_pass(doc)
153
+
154
+ doc = {"doc" => -2147483648}
155
+ assert_doc_pass(doc)
156
+ end
157
+
158
+ def test_ordered_hash
159
+ doc = BSON::OrderedHash.new
160
+ doc["b"] = 1
161
+ doc["a"] = 2
162
+ doc["c"] = 3
163
+ doc["d"] = 4
164
+ assert_doc_pass(doc)
165
+ end
166
+
167
+ def test_object
168
+ doc = {'doc' => {'age' => 42, 'name' => 'Spongebob', 'shoe_size' => 9.5}}
169
+ assert_doc_pass(doc)
170
+ bson = BSON::BSON_CODER.serialize(doc)
171
+ end
172
+
173
+ def test_oid
174
+ doc = {'doc' => ObjectId.new}
175
+ assert_doc_pass(doc)
176
+ end
177
+
178
+ def test_array
179
+ doc = {'doc' => [1, 2, 'a', 'b']}
180
+ assert_doc_pass(doc)
181
+ end
182
+
183
+ def test_regex
184
+ doc = {'doc' => /foobar/i}
185
+ assert_doc_pass(doc)
186
+ end
187
+
188
+ def test_boolean
189
+ doc = {'doc' => true}
190
+ assert_doc_pass(doc)
191
+ end
192
+
193
+ def test_date
194
+ doc = {'date' => Time.now}
195
+ bson = @encoder.serialize(doc)
196
+ doc2 = @decoder.deserialize(bson)
197
+ # Mongo only stores up to the millisecond
198
+ assert_in_delta doc['date'], doc2['date'], 0.001
199
+ end
200
+
201
+ def test_date_returns_as_utc
202
+ doc = {'date' => Time.now}
203
+ bson = @encoder.serialize(doc)
204
+ doc2 = @decoder.deserialize(bson)
205
+ assert doc2['date'].utc?
206
+ end
207
+
208
+ def test_date_before_epoch
209
+ begin
210
+ doc = {'date' => Time.utc(1600)}
211
+ bson = @encoder.serialize(doc)
212
+ doc2 = @decoder.deserialize(bson)
213
+ # Mongo only stores up to the millisecond
214
+ assert_in_delta doc['date'], doc2['date'], 2
215
+ rescue ArgumentError
216
+ # some versions of Ruby won't let you create pre-epoch Time instances
217
+ #
218
+ # TODO figure out how that will work if somebady has saved data
219
+ # w/ early dates already and is just querying for it.
220
+ end
221
+ end
222
+
223
+ def test_exeption_on_using_unsupported_date_class
224
+ [DateTime.now, Date.today, Zone].each do |invalid_date|
225
+ doc = {:date => invalid_date}
226
+ begin
227
+ bson = BSON::BSON_CODER.serialize(doc)
228
+ rescue => e
229
+ ensure
230
+ if !invalid_date.is_a? Time
231
+ assert_equal InvalidDocument, e.class
232
+ assert_match /UTC Time/, e.message
233
+ end
234
+ end
235
+ end
236
+ end
237
+
238
+ def test_dbref
239
+ oid = ObjectId.new
240
+ doc = {}
241
+ doc['dbref'] = DBRef.new('namespace', oid)
242
+ bson = @encoder.serialize(doc)
243
+ doc2 = @decoder.deserialize(bson)
244
+
245
+ # Java doesn't deserialize to DBRefs
246
+ if RUBY_PLATFORM =~ /java/
247
+ assert_equal 'namespace', doc2['dbref']['$ns']
248
+ assert_equal oid, doc2['dbref']['$id']
249
+ else
250
+ assert_equal 'namespace', doc2['dbref'].namespace
251
+ assert_equal oid, doc2['dbref'].object_id
252
+ end
253
+ end
254
+
255
+ def test_symbol
256
+ doc = {'sym' => :foo}
257
+ bson = @encoder.serialize(doc)
258
+ doc2 = @decoder.deserialize(bson)
259
+ assert_equal :foo, doc2['sym']
260
+ end
261
+
262
+ def test_binary
263
+ bin = Binary.new
264
+ 'binstring'.each_byte { |b| bin.put(b) }
265
+
266
+ doc = {'bin' => bin}
267
+ bson = @encoder.serialize(doc)
268
+ doc2 = @decoder.deserialize(bson)
269
+ bin2 = doc2['bin']
270
+ assert_kind_of Binary, bin2
271
+ assert_equal 'binstring', bin2.to_s
272
+ assert_equal Binary::SUBTYPE_BYTES, bin2.subtype
273
+ end
274
+
275
+ def test_binary_with_string
276
+ b = Binary.new('somebinarystring')
277
+ doc = {'bin' => b}
278
+ bson = @encoder.serialize(doc)
279
+ doc2 = @decoder.deserialize(bson)
280
+ bin2 = doc2['bin']
281
+ assert_kind_of Binary, bin2
282
+ assert_equal 'somebinarystring', bin2.to_s
283
+ assert_equal Binary::SUBTYPE_BYTES, bin2.subtype
284
+ end
285
+
286
+ def test_binary_type
287
+ bin = Binary.new([1, 2, 3, 4, 5], Binary::SUBTYPE_USER_DEFINED)
288
+
289
+ doc = {'bin' => bin}
290
+ bson = @encoder.serialize(doc)
291
+ doc2 = @decoder.deserialize(bson)
292
+ bin2 = doc2['bin']
293
+ assert_kind_of Binary, bin2
294
+ assert_equal [1, 2, 3, 4, 5], bin2.to_a
295
+ assert_equal Binary::SUBTYPE_USER_DEFINED, bin2.subtype
296
+ end
297
+
298
+ # Java doesn't support binary subtype 0 yet
299
+ if !(RUBY_PLATFORM =~ /java/)
300
+ def test_binary_subtype_0
301
+ bin = Binary.new([1, 2, 3, 4, 5], Binary::SUBTYPE_SIMPLE)
302
+
303
+ doc = {'bin' => bin}
304
+ bson = @encoder.serialize(doc)
305
+ doc2 = @decoder.deserialize(bson)
306
+ bin2 = doc2['bin']
307
+ assert_kind_of Binary, bin2
308
+ assert_equal [1, 2, 3, 4, 5], bin2.to_a
309
+ assert_equal Binary::SUBTYPE_SIMPLE, bin2.subtype
310
+ end
311
+ end
312
+
313
+ def test_binary_byte_buffer
314
+ bb = Binary.new
315
+ 5.times { |i| bb.put(i + 1) }
316
+
317
+ doc = {'bin' => bb}
318
+ bson = @encoder.serialize(doc)
319
+ doc2 = @decoder.deserialize(bson)
320
+ bin2 = doc2['bin']
321
+ assert_kind_of Binary, bin2
322
+ assert_equal [1, 2, 3, 4, 5], bin2.to_a
323
+ assert_equal Binary::SUBTYPE_BYTES, bin2.subtype
324
+ end
325
+
326
+ def test_put_id_first
327
+ val = BSON::OrderedHash.new
328
+ val['not_id'] = 1
329
+ val['_id'] = 2
330
+ roundtrip = @decoder.deserialize(@encoder.serialize(val, false, true).to_s)
331
+ assert_kind_of BSON::OrderedHash, roundtrip
332
+ assert_equal '_id', roundtrip.keys.first
333
+
334
+ val = {'a' => 'foo', 'b' => 'bar', :_id => 42, 'z' => 'hello'}
335
+ roundtrip = @decoder.deserialize(@encoder.serialize(val, false, true).to_s)
336
+ assert_kind_of BSON::OrderedHash, roundtrip
337
+ assert_equal '_id', roundtrip.keys.first
338
+ end
339
+
340
+ def test_nil_id
341
+ doc = {"_id" => nil}
342
+ assert_doc_pass(doc)
343
+ end
344
+
345
+ if !(RUBY_PLATFORM =~ /java/)
346
+ def test_timestamp
347
+ val = {"test" => [4, 20]}
348
+ assert_equal val, @decoder.deserialize([0x13, 0x00, 0x00, 0x00,
349
+ 0x11, 0x74, 0x65, 0x73,
350
+ 0x74, 0x00, 0x04, 0x00,
351
+ 0x00, 0x00, 0x14, 0x00,
352
+ 0x00, 0x00, 0x00])
353
+
354
+ end
355
+ end
356
+
357
+ def test_overflow
358
+ doc = {"x" => 2**75}
359
+ assert_raise RangeError do
360
+ bson = @encoder.serialize(doc)
361
+ end
362
+
363
+ doc = {"x" => 9223372036854775}
364
+ assert_doc_pass(doc)
365
+
366
+ doc = {"x" => 9223372036854775807}
367
+ assert_doc_pass(doc)
368
+
369
+ doc["x"] = doc["x"] + 1
370
+ assert_raise RangeError do
371
+ bson = @encoder.serialize(doc)
372
+ end
373
+
374
+ doc = {"x" => -9223372036854775}
375
+ assert_doc_pass(doc)
376
+
377
+ doc = {"x" => -9223372036854775808}
378
+ assert_doc_pass(doc)
379
+
380
+ doc["x"] = doc["x"] - 1
381
+ assert_raise RangeError do
382
+ bson = BSON::BSON_CODER.serialize(doc)
383
+ end
384
+ end
385
+
386
+ def test_invalid_numeric_types
387
+ [BigDecimal.new("1.0"), Complex(0, 1), Rational(2, 3)].each do |type|
388
+ doc = {"x" => type}
389
+ begin
390
+ @encoder.serialize(doc)
391
+ rescue => e
392
+ ensure
393
+ assert_equal InvalidDocument, e.class
394
+ assert_match /Cannot serialize/, e.message
395
+ end
396
+ end
397
+ end
398
+
399
+ def test_do_not_change_original_object
400
+ val = BSON::OrderedHash.new
401
+ val['not_id'] = 1
402
+ val['_id'] = 2
403
+ assert val.keys.include?('_id')
404
+ @encoder.serialize(val)
405
+ assert val.keys.include?('_id')
406
+
407
+ val = {'a' => 'foo', 'b' => 'bar', :_id => 42, 'z' => 'hello'}
408
+ assert val.keys.include?(:_id)
409
+ @encoder.serialize(val)
410
+ assert val.keys.include?(:_id)
411
+ end
412
+
413
+ # note we only test for _id here because in the general case we will
414
+ # write duplicates for :key and "key". _id is a special case because
415
+ # we call has_key? to check for it's existence rather than just iterating
416
+ # over it like we do for the rest of the keys. thus, things like
417
+ # HashWithIndifferentAccess can cause problems for _id but not for other
418
+ # keys. rather than require rails to test with HWIA directly, we do this
419
+ # somewhat hacky test.
420
+ def test_no_duplicate_id
421
+ dup = {"_id" => "foo", :_id => "foo"}
422
+ one = {"_id" => "foo"}
423
+
424
+ assert_equal @encoder.serialize(one).to_a, @encoder.serialize(dup).to_a
425
+ end
426
+
427
+ def test_no_duplicate_id_when_moving_id
428
+ dup = {"_id" => "foo", :_id => "foo"}
429
+ one = {:_id => "foo"}
430
+
431
+ assert_equal @encoder.serialize(one, false, true).to_s, @encoder.serialize(dup, false, true).to_s
432
+ end
433
+
434
+ def test_null_character
435
+ doc = {"a" => "\x00"}
436
+
437
+ assert_doc_pass(doc)
438
+
439
+ assert_raise InvalidDocument do
440
+ @encoder.serialize({"\x00" => "a"})
441
+ end
442
+
443
+ assert_raise InvalidDocument do
444
+ @encoder.serialize({"a" => (Regexp.compile "ab\x00c")})
445
+ end
446
+ end
447
+
448
+ def test_max_key
449
+ doc = {"a" => MaxKey.new}
450
+ assert_doc_pass(doc)
451
+ end
452
+
453
+ def test_min_key
454
+ doc = {"a" => MinKey.new}
455
+ assert_doc_pass(doc)
456
+ end
457
+
458
+ def test_invalid_object
459
+ o = Object.new
460
+ assert_raise InvalidDocument do
461
+ @encoder.serialize({:foo => o})
462
+ end
463
+
464
+ assert_raise InvalidDocument do
465
+ @encoder.serialize({:foo => Date.today})
466
+ end
467
+ end
468
+
469
+ def test_move_id
470
+ a = BSON::OrderedHash.new
471
+ a['text'] = 'abc'
472
+ a['key'] = 'abc'
473
+ a['_id'] = 1
474
+
475
+
476
+ assert_equal ")\000\000\000\020_id\000\001\000\000\000\002text" +
477
+ "\000\004\000\000\000abc\000\002key\000\004\000\000\000abc\000\000",
478
+ @encoder.serialize(a, false, true).to_s
479
+
480
+ # Java doesn't support this. Isn't actually necessary.
481
+ if !(RUBY_PLATFORM =~ /java/)
482
+ assert_equal ")\000\000\000\002text\000\004\000\000\000abc\000\002key" +
483
+ "\000\004\000\000\000abc\000\020_id\000\001\000\000\000\000",
484
+ @encoder.serialize(a, false, false).to_s
485
+ end
486
+ end
487
+
488
+ def test_move_id_with_nested_doc
489
+ b = BSON::OrderedHash.new
490
+ b['text'] = 'abc'
491
+ b['_id'] = 2
492
+ c = BSON::OrderedHash.new
493
+ c['text'] = 'abc'
494
+ c['hash'] = b
495
+ c['_id'] = 3
496
+ assert_equal ">\000\000\000\020_id\000\003\000\000\000\002text" +
497
+ "\000\004\000\000\000abc\000\003hash\000\034\000\000" +
498
+ "\000\002text\000\004\000\000\000abc\000\020_id\000\002\000\000\000\000\000",
499
+ @encoder.serialize(c, false, true).to_s
500
+
501
+ # Java doesn't support this. Isn't actually necessary.
502
+ if !(RUBY_PLATFORM =~ /java/)
503
+ assert_equal ">\000\000\000\002text\000\004\000\000\000abc\000\003hash" +
504
+ "\000\034\000\000\000\002text\000\004\000\000\000abc\000\020_id" +
505
+ "\000\002\000\000\000\000\020_id\000\003\000\000\000\000",
506
+ @encoder.serialize(c, false, false).to_s
507
+ end
508
+ end
509
+
510
+ # Mocking this class for testing
511
+ class ::HashWithIndifferentAccess < Hash; end
512
+
513
+ def test_keep_id_with_hash_with_indifferent_access
514
+ doc = HashWithIndifferentAccess.new
515
+ embedded = HashWithIndifferentAccess.new
516
+ embedded['_id'] = ObjectId.new
517
+ doc['_id'] = ObjectId.new
518
+ doc['embedded'] = [embedded]
519
+ @encoder.serialize(doc, false, true).to_a
520
+ assert doc.has_key?("_id")
521
+ assert doc['embedded'][0].has_key?("_id")
522
+
523
+ doc['_id'] = ObjectId.new
524
+ @encoder.serialize(doc, false, true).to_a
525
+ assert doc.has_key?("_id")
526
+ end
527
+
528
+ end