mongo 1.0 → 1.1.5
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/LICENSE.txt +1 -13
- data/{README.rdoc → README.md} +129 -149
- data/Rakefile +94 -58
- data/bin/mongo_console +21 -0
- data/docs/1.0_UPGRADE.md +21 -0
- data/docs/CREDITS.md +123 -0
- data/docs/FAQ.md +112 -0
- data/docs/GridFS.md +158 -0
- data/docs/HISTORY.md +185 -0
- data/docs/REPLICA_SETS.md +75 -0
- data/docs/TUTORIAL.md +247 -0
- data/docs/WRITE_CONCERN.md +28 -0
- data/lib/mongo/collection.rb +225 -105
- data/lib/mongo/connection.rb +374 -315
- data/lib/mongo/cursor.rb +122 -77
- data/lib/mongo/db.rb +109 -85
- data/lib/mongo/exceptions.rb +6 -0
- data/lib/mongo/gridfs/grid.rb +19 -11
- data/lib/mongo/gridfs/grid_ext.rb +36 -9
- data/lib/mongo/gridfs/grid_file_system.rb +15 -9
- data/lib/mongo/gridfs/grid_io.rb +49 -16
- data/lib/mongo/gridfs/grid_io_fix.rb +38 -0
- data/lib/mongo/repl_set_connection.rb +290 -0
- data/lib/mongo/util/conversions.rb +3 -1
- data/lib/mongo/util/core_ext.rb +17 -4
- data/lib/mongo/util/pool.rb +125 -0
- data/lib/mongo/util/server_version.rb +2 -0
- data/lib/mongo/util/support.rb +12 -0
- data/lib/mongo/util/uri_parser.rb +71 -0
- data/lib/mongo.rb +23 -7
- data/{mongo-ruby-driver.gemspec → mongo.gemspec} +9 -7
- data/test/auxillary/1.4_features.rb +2 -2
- data/test/auxillary/authentication_test.rb +1 -1
- data/test/auxillary/autoreconnect_test.rb +1 -1
- data/test/{slave_connection_test.rb → auxillary/slave_connection_test.rb} +6 -6
- data/test/bson/binary_test.rb +15 -0
- data/test/bson/bson_test.rb +537 -0
- data/test/bson/byte_buffer_test.rb +190 -0
- data/test/bson/hash_with_indifferent_access_test.rb +38 -0
- data/test/bson/json_test.rb +17 -0
- data/test/bson/object_id_test.rb +141 -0
- data/test/bson/ordered_hash_test.rb +197 -0
- data/test/collection_test.rb +195 -15
- data/test/connection_test.rb +93 -56
- data/test/conversions_test.rb +1 -1
- data/test/cursor_fail_test.rb +75 -0
- data/test/cursor_message_test.rb +43 -0
- data/test/cursor_test.rb +93 -32
- data/test/db_api_test.rb +28 -55
- data/test/db_connection_test.rb +2 -3
- data/test/db_test.rb +45 -40
- data/test/grid_file_system_test.rb +14 -6
- data/test/grid_io_test.rb +36 -7
- data/test/grid_test.rb +54 -10
- data/test/replica_sets/connect_test.rb +84 -0
- data/test/replica_sets/count_test.rb +35 -0
- data/test/{replica → replica_sets}/insert_test.rb +17 -14
- data/test/replica_sets/pooled_insert_test.rb +55 -0
- data/test/replica_sets/query_secondaries.rb +80 -0
- data/test/replica_sets/query_test.rb +41 -0
- data/test/replica_sets/replication_ack_test.rb +64 -0
- data/test/replica_sets/rs_test_helper.rb +29 -0
- data/test/safe_test.rb +68 -0
- data/test/support/hash_with_indifferent_access.rb +199 -0
- data/test/support/keys.rb +45 -0
- data/test/support_test.rb +19 -0
- data/test/test_helper.rb +53 -15
- data/test/threading/{test_threading_large_pool.rb → threading_with_large_pool_test.rb} +2 -2
- data/test/threading_test.rb +2 -2
- data/test/tools/repl_set_manager.rb +241 -0
- data/test/tools/test.rb +13 -0
- data/test/unit/collection_test.rb +70 -7
- data/test/unit/connection_test.rb +18 -39
- data/test/unit/cursor_test.rb +7 -8
- data/test/unit/db_test.rb +14 -17
- data/test/unit/grid_test.rb +49 -0
- data/test/unit/pool_test.rb +9 -0
- data/test/unit/repl_set_connection_test.rb +82 -0
- data/test/unit/safe_test.rb +125 -0
- metadata +132 -51
- data/bin/bson_benchmark.rb +0 -59
- data/bin/fail_if_no_c.rb +0 -11
- data/examples/admin.rb +0 -43
- data/examples/capped.rb +0 -22
- data/examples/cursor.rb +0 -48
- data/examples/gridfs.rb +0 -44
- data/examples/index_test.rb +0 -126
- data/examples/info.rb +0 -31
- data/examples/queries.rb +0 -70
- data/examples/simple.rb +0 -24
- data/examples/strict.rb +0 -35
- data/examples/types.rb +0 -36
- data/test/replica/count_test.rb +0 -34
- data/test/replica/pooled_insert_test.rb +0 -54
- data/test/replica/query_test.rb +0 -39
|
@@ -0,0 +1,537 @@
|
|
|
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
|
+
def initialize(utc_time, zone)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
Zone = ActiveSupport::TimeWithZone.new(Time.now.utc, 'EST')
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
class BSONTest < Test::Unit::TestCase
|
|
23
|
+
|
|
24
|
+
include BSON
|
|
25
|
+
|
|
26
|
+
def setup
|
|
27
|
+
@encoder = BSON::BSON_CODER
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def assert_doc_pass(doc, options={})
|
|
31
|
+
bson = @encoder.serialize(doc)
|
|
32
|
+
if options[:debug]
|
|
33
|
+
puts "DEBUGGING DOC:"
|
|
34
|
+
p bson.to_a
|
|
35
|
+
puts "DESERIALIZES TO:"
|
|
36
|
+
end
|
|
37
|
+
assert_equal @encoder.serialize(doc).to_a, bson.to_a
|
|
38
|
+
assert_equal doc, @encoder.deserialize(bson)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def test_require_hash
|
|
42
|
+
assert_raise_error InvalidDocument, "takes a Hash" do
|
|
43
|
+
BSON.serialize('foo')
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
assert_raise_error InvalidDocument, "takes a Hash" do
|
|
47
|
+
BSON.serialize(Object.new)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
assert_raise_error InvalidDocument, "takes a Hash" do
|
|
51
|
+
BSON.serialize(Set.new)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def test_string
|
|
56
|
+
doc = {'doc' => 'hello, world'}
|
|
57
|
+
assert_doc_pass(doc)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def test_valid_utf8_string
|
|
61
|
+
doc = {'doc' => 'aé'}
|
|
62
|
+
assert_doc_pass(doc)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def test_valid_utf8_key
|
|
66
|
+
doc = {'aé' => 'hello'}
|
|
67
|
+
assert_doc_pass(doc)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def test_document_length
|
|
71
|
+
doc = {'name' => 'a' * 5 * 1024 * 1024}
|
|
72
|
+
assert_raise InvalidDocument do
|
|
73
|
+
assert @encoder.serialize(doc)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def test_round_trip
|
|
78
|
+
doc = {'doc' => 123}
|
|
79
|
+
@encoder.deserialize(@encoder.serialize(doc))
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# In 1.8 we test that other string encodings raise an exception.
|
|
83
|
+
# In 1.9 we test that they get auto-converted.
|
|
84
|
+
if RUBY_VERSION < '1.9'
|
|
85
|
+
if ! RUBY_PLATFORM =~ /java/
|
|
86
|
+
require 'iconv'
|
|
87
|
+
def test_non_utf8_string
|
|
88
|
+
string = Iconv.conv('iso-8859-1', 'utf-8', 'aé')
|
|
89
|
+
doc = {'doc' => string}
|
|
90
|
+
assert_doc_pass(doc)
|
|
91
|
+
assert_raise InvalidStringEncoding do
|
|
92
|
+
@encoder.serialize(doc)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def test_non_utf8_key
|
|
97
|
+
key = Iconv.conv('iso-8859-1', 'utf-8', 'aé')
|
|
98
|
+
doc = {key => 'hello'}
|
|
99
|
+
assert_raise InvalidStringEncoding do
|
|
100
|
+
@encoder.serialize(doc)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
else
|
|
105
|
+
def test_non_utf8_string
|
|
106
|
+
bson = BSON::BSON_CODER.serialize({'str' => 'aé'.encode('iso-8859-1')})
|
|
107
|
+
result = BSON::BSON_CODER.deserialize(bson)['str']
|
|
108
|
+
assert_equal 'aé', result
|
|
109
|
+
assert_equal 'UTF-8', result.encoding.name
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def test_non_utf8_key
|
|
113
|
+
bson = BSON::BSON_CODER.serialize({'aé'.encode('iso-8859-1') => 'hello'})
|
|
114
|
+
assert_equal 'hello', BSON::BSON_CODER.deserialize(bson)['aé']
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Based on a test from sqlite3-ruby
|
|
118
|
+
def test_default_internal_is_honored
|
|
119
|
+
before_enc = Encoding.default_internal
|
|
120
|
+
|
|
121
|
+
str = "壁に耳あり、障子に目あり"
|
|
122
|
+
bson = BSON::BSON_CODER.serialize("x" => str)
|
|
123
|
+
|
|
124
|
+
Encoding.default_internal = 'EUC-JP'
|
|
125
|
+
out = BSON::BSON_CODER.deserialize(bson)["x"]
|
|
126
|
+
|
|
127
|
+
assert_equal Encoding.default_internal, out.encoding
|
|
128
|
+
assert_equal str.encode('EUC-JP'), out
|
|
129
|
+
assert_equal str, out.encode(str.encoding)
|
|
130
|
+
ensure
|
|
131
|
+
Encoding.default_internal = before_enc
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def test_code
|
|
136
|
+
doc = {'$where' => Code.new('this.a.b < this.b')}
|
|
137
|
+
assert_doc_pass(doc)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def test_code_with_scope
|
|
141
|
+
doc = {'$where' => Code.new('this.a.b < this.b', {'foo' => 1})}
|
|
142
|
+
assert_doc_pass(doc)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def test_double
|
|
146
|
+
doc = {'doc' => 41.25}
|
|
147
|
+
assert_doc_pass(doc)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def test_int
|
|
151
|
+
doc = {'doc' => 42}
|
|
152
|
+
assert_doc_pass(doc)
|
|
153
|
+
|
|
154
|
+
doc = {"doc" => -5600}
|
|
155
|
+
assert_doc_pass(doc)
|
|
156
|
+
|
|
157
|
+
doc = {"doc" => 2147483647}
|
|
158
|
+
assert_doc_pass(doc)
|
|
159
|
+
|
|
160
|
+
doc = {"doc" => -2147483648}
|
|
161
|
+
assert_doc_pass(doc)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def test_ordered_hash
|
|
165
|
+
doc = BSON::OrderedHash.new
|
|
166
|
+
doc["b"] = 1
|
|
167
|
+
doc["a"] = 2
|
|
168
|
+
doc["c"] = 3
|
|
169
|
+
doc["d"] = 4
|
|
170
|
+
assert_doc_pass(doc)
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def test_object
|
|
174
|
+
doc = {'doc' => {'age' => 42, 'name' => 'Spongebob', 'shoe_size' => 9.5}}
|
|
175
|
+
assert_doc_pass(doc)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def test_embedded_document_with_nil
|
|
179
|
+
doc = {'doc' => {'age' => 42, 'name' => nil, 'shoe_size' => 9.5}}
|
|
180
|
+
assert_doc_pass(doc)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def test_embedded_document_with_date
|
|
184
|
+
doc = {'doc' => {'age' => 42, 'date' => Time.now.utc, 'shoe_size' => 9.5}}
|
|
185
|
+
bson = @encoder.serialize(doc)
|
|
186
|
+
doc2 = @encoder.deserialize(bson)
|
|
187
|
+
assert doc['doc']
|
|
188
|
+
assert_equal 42, doc['doc']['age']
|
|
189
|
+
assert_equal 9.5, doc['doc']['shoe_size']
|
|
190
|
+
assert_in_delta Time.now, doc['doc']['date'], 1
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def test_oid
|
|
194
|
+
doc = {'doc' => ObjectId.new}
|
|
195
|
+
assert_doc_pass(doc)
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def test_array
|
|
199
|
+
doc = {'doc' => [1, 2, 'a', 'b']}
|
|
200
|
+
assert_doc_pass(doc)
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def test_regex
|
|
204
|
+
doc = {'doc' => /foobar/i}
|
|
205
|
+
assert_doc_pass(doc)
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def test_boolean
|
|
209
|
+
doc = {'doc' => true}
|
|
210
|
+
assert_doc_pass(doc)
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def test_date
|
|
214
|
+
doc = {'date' => Time.now}
|
|
215
|
+
bson = @encoder.serialize(doc)
|
|
216
|
+
doc2 = @encoder.deserialize(bson)
|
|
217
|
+
# Mongo only stores up to the millisecond
|
|
218
|
+
assert_in_delta doc['date'], doc2['date'], 0.001
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def test_date_returns_as_utc
|
|
222
|
+
doc = {'date' => Time.now}
|
|
223
|
+
bson = @encoder.serialize(doc)
|
|
224
|
+
doc2 = @encoder.deserialize(bson)
|
|
225
|
+
assert doc2['date'].utc?
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def test_date_before_epoch
|
|
229
|
+
begin
|
|
230
|
+
doc = {'date' => Time.utc(1600)}
|
|
231
|
+
bson = @encoder.serialize(doc)
|
|
232
|
+
doc2 = @encoder.deserialize(bson)
|
|
233
|
+
# Mongo only stores up to the millisecond
|
|
234
|
+
assert_in_delta doc['date'], doc2['date'], 2
|
|
235
|
+
rescue ArgumentError
|
|
236
|
+
# some versions of Ruby won't let you create pre-epoch Time instances
|
|
237
|
+
#
|
|
238
|
+
# TODO figure out how that will work if somebady has saved data
|
|
239
|
+
# w/ early dates already and is just querying for it.
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
def test_exeption_on_using_unsupported_date_class
|
|
244
|
+
[DateTime.now, Date.today, Zone].each do |invalid_date|
|
|
245
|
+
doc = {:date => invalid_date}
|
|
246
|
+
begin
|
|
247
|
+
bson = BSON::BSON_CODER.serialize(doc)
|
|
248
|
+
rescue => e
|
|
249
|
+
ensure
|
|
250
|
+
if !invalid_date.is_a? Time
|
|
251
|
+
assert_equal InvalidDocument, e.class
|
|
252
|
+
assert_match /UTC Time/, e.message
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
def test_dbref
|
|
259
|
+
oid = ObjectId.new
|
|
260
|
+
doc = {}
|
|
261
|
+
doc['dbref'] = DBRef.new('namespace', oid)
|
|
262
|
+
bson = @encoder.serialize(doc)
|
|
263
|
+
doc2 = @encoder.deserialize(bson)
|
|
264
|
+
|
|
265
|
+
# Java doesn't deserialize to DBRefs
|
|
266
|
+
if RUBY_PLATFORM =~ /java/
|
|
267
|
+
assert_equal 'namespace', doc2['dbref']['$ns']
|
|
268
|
+
assert_equal oid, doc2['dbref']['$id']
|
|
269
|
+
else
|
|
270
|
+
assert_equal 'namespace', doc2['dbref'].namespace
|
|
271
|
+
assert_equal oid, doc2['dbref'].object_id
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
def test_symbol
|
|
276
|
+
doc = {'sym' => :foo}
|
|
277
|
+
bson = @encoder.serialize(doc)
|
|
278
|
+
doc2 = @encoder.deserialize(bson)
|
|
279
|
+
assert_equal :foo, doc2['sym']
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
def test_binary
|
|
283
|
+
bin = Binary.new
|
|
284
|
+
'binstring'.each_byte { |b| bin.put(b) }
|
|
285
|
+
|
|
286
|
+
doc = {'bin' => bin}
|
|
287
|
+
bson = @encoder.serialize(doc)
|
|
288
|
+
doc2 = @encoder.deserialize(bson)
|
|
289
|
+
bin2 = doc2['bin']
|
|
290
|
+
assert_kind_of Binary, bin2
|
|
291
|
+
assert_equal 'binstring', bin2.to_s
|
|
292
|
+
assert_equal Binary::SUBTYPE_BYTES, bin2.subtype
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
def test_binary_with_string
|
|
296
|
+
b = Binary.new('somebinarystring')
|
|
297
|
+
doc = {'bin' => b}
|
|
298
|
+
bson = @encoder.serialize(doc)
|
|
299
|
+
doc2 = @encoder.deserialize(bson)
|
|
300
|
+
bin2 = doc2['bin']
|
|
301
|
+
assert_kind_of Binary, bin2
|
|
302
|
+
assert_equal 'somebinarystring', bin2.to_s
|
|
303
|
+
assert_equal Binary::SUBTYPE_BYTES, bin2.subtype
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
def test_binary_type
|
|
307
|
+
bin = Binary.new([1, 2, 3, 4, 5], Binary::SUBTYPE_USER_DEFINED)
|
|
308
|
+
|
|
309
|
+
doc = {'bin' => bin}
|
|
310
|
+
bson = @encoder.serialize(doc)
|
|
311
|
+
doc2 = @encoder.deserialize(bson)
|
|
312
|
+
bin2 = doc2['bin']
|
|
313
|
+
assert_kind_of Binary, bin2
|
|
314
|
+
assert_equal [1, 2, 3, 4, 5], bin2.to_a
|
|
315
|
+
assert_equal Binary::SUBTYPE_USER_DEFINED, bin2.subtype
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
# Java doesn't support binary subtype 0 yet
|
|
319
|
+
if !(RUBY_PLATFORM =~ /java/)
|
|
320
|
+
def test_binary_subtype_0
|
|
321
|
+
bin = Binary.new([1, 2, 3, 4, 5], Binary::SUBTYPE_SIMPLE)
|
|
322
|
+
|
|
323
|
+
doc = {'bin' => bin}
|
|
324
|
+
bson = @encoder.serialize(doc)
|
|
325
|
+
doc2 = @encoder.deserialize(bson)
|
|
326
|
+
bin2 = doc2['bin']
|
|
327
|
+
assert_kind_of Binary, bin2
|
|
328
|
+
assert_equal [1, 2, 3, 4, 5], bin2.to_a
|
|
329
|
+
assert_equal Binary::SUBTYPE_SIMPLE, bin2.subtype
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
def test_binary_byte_buffer
|
|
334
|
+
bb = Binary.new
|
|
335
|
+
5.times { |i| bb.put(i + 1) }
|
|
336
|
+
|
|
337
|
+
doc = {'bin' => bb}
|
|
338
|
+
bson = @encoder.serialize(doc)
|
|
339
|
+
doc2 = @encoder.deserialize(bson)
|
|
340
|
+
bin2 = doc2['bin']
|
|
341
|
+
assert_kind_of Binary, bin2
|
|
342
|
+
assert_equal [1, 2, 3, 4, 5], bin2.to_a
|
|
343
|
+
assert_equal Binary::SUBTYPE_BYTES, bin2.subtype
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
def test_put_id_first
|
|
347
|
+
val = BSON::OrderedHash.new
|
|
348
|
+
val['not_id'] = 1
|
|
349
|
+
val['_id'] = 2
|
|
350
|
+
roundtrip = @encoder.deserialize(@encoder.serialize(val, false, true).to_s)
|
|
351
|
+
assert_kind_of BSON::OrderedHash, roundtrip
|
|
352
|
+
assert_equal '_id', roundtrip.keys.first
|
|
353
|
+
|
|
354
|
+
val = {'a' => 'foo', 'b' => 'bar', :_id => 42, 'z' => 'hello'}
|
|
355
|
+
roundtrip = @encoder.deserialize(@encoder.serialize(val, false, true).to_s)
|
|
356
|
+
assert_kind_of BSON::OrderedHash, roundtrip
|
|
357
|
+
assert_equal '_id', roundtrip.keys.first
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
def test_nil_id
|
|
361
|
+
doc = {"_id" => nil}
|
|
362
|
+
assert_doc_pass(doc)
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
if !(RUBY_PLATFORM =~ /java/)
|
|
366
|
+
def test_timestamp
|
|
367
|
+
val = {"test" => [4, 20]}
|
|
368
|
+
assert_equal val, @encoder.deserialize([0x13, 0x00, 0x00, 0x00,
|
|
369
|
+
0x11, 0x74, 0x65, 0x73,
|
|
370
|
+
0x74, 0x00, 0x04, 0x00,
|
|
371
|
+
0x00, 0x00, 0x14, 0x00,
|
|
372
|
+
0x00, 0x00, 0x00])
|
|
373
|
+
|
|
374
|
+
end
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
def test_overflow
|
|
378
|
+
doc = {"x" => 2**75}
|
|
379
|
+
assert_raise RangeError do
|
|
380
|
+
bson = @encoder.serialize(doc)
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
doc = {"x" => 9223372036854775}
|
|
384
|
+
assert_doc_pass(doc)
|
|
385
|
+
|
|
386
|
+
doc = {"x" => 9223372036854775807}
|
|
387
|
+
assert_doc_pass(doc)
|
|
388
|
+
|
|
389
|
+
doc["x"] = doc["x"] + 1
|
|
390
|
+
assert_raise RangeError do
|
|
391
|
+
bson = @encoder.serialize(doc)
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
doc = {"x" => -9223372036854775}
|
|
395
|
+
assert_doc_pass(doc)
|
|
396
|
+
|
|
397
|
+
doc = {"x" => -9223372036854775808}
|
|
398
|
+
assert_doc_pass(doc)
|
|
399
|
+
|
|
400
|
+
doc["x"] = doc["x"] - 1
|
|
401
|
+
assert_raise RangeError do
|
|
402
|
+
bson = BSON::BSON_CODER.serialize(doc)
|
|
403
|
+
end
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
def test_invalid_numeric_types
|
|
407
|
+
[BigDecimal.new("1.0"), Complex(0, 1), Rational(2, 3)].each do |type|
|
|
408
|
+
doc = {"x" => type}
|
|
409
|
+
begin
|
|
410
|
+
@encoder.serialize(doc)
|
|
411
|
+
rescue => e
|
|
412
|
+
ensure
|
|
413
|
+
assert_equal InvalidDocument, e.class
|
|
414
|
+
assert_match /Cannot serialize/, e.message
|
|
415
|
+
end
|
|
416
|
+
end
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
def test_do_not_change_original_object
|
|
420
|
+
val = BSON::OrderedHash.new
|
|
421
|
+
val['not_id'] = 1
|
|
422
|
+
val['_id'] = 2
|
|
423
|
+
assert val.keys.include?('_id')
|
|
424
|
+
@encoder.serialize(val)
|
|
425
|
+
assert val.keys.include?('_id')
|
|
426
|
+
|
|
427
|
+
val = {'a' => 'foo', 'b' => 'bar', :_id => 42, 'z' => 'hello'}
|
|
428
|
+
assert val.keys.include?(:_id)
|
|
429
|
+
@encoder.serialize(val)
|
|
430
|
+
assert val.keys.include?(:_id)
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
# note we only test for _id here because in the general case we will
|
|
434
|
+
# write duplicates for :key and "key". _id is a special case because
|
|
435
|
+
# we call has_key? to check for it's existence rather than just iterating
|
|
436
|
+
# over it like we do for the rest of the keys. thus, things like
|
|
437
|
+
# HashWithIndifferentAccess can cause problems for _id but not for other
|
|
438
|
+
# keys. rather than require rails to test with HWIA directly, we do this
|
|
439
|
+
# somewhat hacky test.
|
|
440
|
+
#
|
|
441
|
+
# Note that the driver only eliminates duplicate ids when move_id is true.
|
|
442
|
+
def test_no_duplicate_id
|
|
443
|
+
dup = {"_id" => "foo", :_id => "foo"}
|
|
444
|
+
one = {"_id" => "foo"}
|
|
445
|
+
|
|
446
|
+
assert_equal @encoder.serialize(one, false, true).to_a, @encoder.serialize(dup, false, true).to_a
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
def test_duplicate_keys
|
|
450
|
+
#dup = {"_foo" => "foo", :_foo => "foo"}
|
|
451
|
+
#one = {"_foo" => "foo"}
|
|
452
|
+
|
|
453
|
+
#assert_equal @encoder.serialize(one).to_a, @encoder.serialize(dup).to_a
|
|
454
|
+
warn "Pending test for duplicate keys"
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
def test_no_duplicate_id_when_moving_id
|
|
458
|
+
dup = {"_id" => "foo", :_id => "foo"}
|
|
459
|
+
one = {:_id => "foo"}
|
|
460
|
+
|
|
461
|
+
assert_equal @encoder.serialize(one, false, true).to_s, @encoder.serialize(dup, false, true).to_s
|
|
462
|
+
end
|
|
463
|
+
|
|
464
|
+
def test_null_character
|
|
465
|
+
doc = {"a" => "\x00"}
|
|
466
|
+
|
|
467
|
+
assert_doc_pass(doc)
|
|
468
|
+
|
|
469
|
+
assert_raise InvalidDocument do
|
|
470
|
+
@encoder.serialize({"\x00" => "a"})
|
|
471
|
+
end
|
|
472
|
+
|
|
473
|
+
assert_raise InvalidDocument do
|
|
474
|
+
@encoder.serialize({"a" => (Regexp.compile "ab\x00c")})
|
|
475
|
+
end
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
def test_max_key
|
|
479
|
+
doc = {"a" => MaxKey.new}
|
|
480
|
+
assert_doc_pass(doc)
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
def test_min_key
|
|
484
|
+
doc = {"a" => MinKey.new}
|
|
485
|
+
assert_doc_pass(doc)
|
|
486
|
+
end
|
|
487
|
+
|
|
488
|
+
def test_invalid_object
|
|
489
|
+
o = Object.new
|
|
490
|
+
assert_raise InvalidDocument do
|
|
491
|
+
@encoder.serialize({:foo => o})
|
|
492
|
+
end
|
|
493
|
+
|
|
494
|
+
assert_raise InvalidDocument do
|
|
495
|
+
@encoder.serialize({:foo => Date.today})
|
|
496
|
+
end
|
|
497
|
+
end
|
|
498
|
+
|
|
499
|
+
def test_move_id
|
|
500
|
+
a = BSON::OrderedHash.new
|
|
501
|
+
a['text'] = 'abc'
|
|
502
|
+
a['key'] = 'abc'
|
|
503
|
+
a['_id'] = 1
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
assert_equal ")\000\000\000\020_id\000\001\000\000\000\002text" +
|
|
507
|
+
"\000\004\000\000\000abc\000\002key\000\004\000\000\000abc\000\000",
|
|
508
|
+
@encoder.serialize(a, false, true).to_s
|
|
509
|
+
|
|
510
|
+
assert_equal ")\000\000\000\002text\000\004\000\000\000abc\000\002key" +
|
|
511
|
+
"\000\004\000\000\000abc\000\020_id\000\001\000\000\000\000",
|
|
512
|
+
@encoder.serialize(a, false, false).to_s
|
|
513
|
+
end
|
|
514
|
+
|
|
515
|
+
def test_move_id_with_nested_doc
|
|
516
|
+
b = BSON::OrderedHash.new
|
|
517
|
+
b['text'] = 'abc'
|
|
518
|
+
b['_id'] = 2
|
|
519
|
+
c = BSON::OrderedHash.new
|
|
520
|
+
c['text'] = 'abc'
|
|
521
|
+
c['hash'] = b
|
|
522
|
+
c['_id'] = 3
|
|
523
|
+
assert_equal ">\000\000\000\020_id\000\003\000\000\000\002text" +
|
|
524
|
+
"\000\004\000\000\000abc\000\003hash\000\034\000\000" +
|
|
525
|
+
"\000\002text\000\004\000\000\000abc\000\020_id\000\002\000\000\000\000\000",
|
|
526
|
+
@encoder.serialize(c, false, true).to_s
|
|
527
|
+
|
|
528
|
+
# Java doesn't support this. Isn't actually necessary.
|
|
529
|
+
if !(RUBY_PLATFORM =~ /java/)
|
|
530
|
+
assert_equal ">\000\000\000\002text\000\004\000\000\000abc\000\003hash" +
|
|
531
|
+
"\000\034\000\000\000\002text\000\004\000\000\000abc\000\020_id" +
|
|
532
|
+
"\000\002\000\000\000\000\020_id\000\003\000\000\000\000",
|
|
533
|
+
@encoder.serialize(c, false, false).to_s
|
|
534
|
+
end
|
|
535
|
+
end
|
|
536
|
+
|
|
537
|
+
end
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# encoding: binary
|
|
2
|
+
require './test/test_helper'
|
|
3
|
+
|
|
4
|
+
class ByteBufferTest < Test::Unit::TestCase
|
|
5
|
+
include BSON
|
|
6
|
+
|
|
7
|
+
def setup
|
|
8
|
+
@buf = ByteBuffer.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def test_initial_state
|
|
12
|
+
assert_equal 0, @buf.position
|
|
13
|
+
assert_equal [], @buf.to_a
|
|
14
|
+
assert_equal "", @buf.to_s
|
|
15
|
+
assert_equal 0, @buf.length
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def test_nil_get_returns_one_byte
|
|
19
|
+
@buf.put_array([1, 2, 3, 4])
|
|
20
|
+
@buf.rewind
|
|
21
|
+
assert_equal 1, @buf.get
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def test_one_get_returns_array_length_one
|
|
25
|
+
@buf.put_array([1, 2, 3, 4])
|
|
26
|
+
@buf.rewind
|
|
27
|
+
assert_equal [1], @buf.get(1)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def test_zero_get_returns_empty_array
|
|
31
|
+
@buf.put_array([1, 2, 3, 4])
|
|
32
|
+
@buf.rewind
|
|
33
|
+
assert_equal [], @buf.get(0)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def test_length
|
|
37
|
+
@buf.put_int 3
|
|
38
|
+
assert_equal 4, @buf.length
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def test_default_order
|
|
42
|
+
assert_equal :little_endian, @buf.order
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def test_long_length
|
|
46
|
+
@buf.put_long 1027
|
|
47
|
+
assert_equal 8, @buf.length
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def test_get_long
|
|
51
|
+
@buf.put_long 1027
|
|
52
|
+
@buf.rewind
|
|
53
|
+
assert_equal 1027, @buf.get_long
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def test_get_double
|
|
57
|
+
@buf.put_double 41.2
|
|
58
|
+
@buf.rewind
|
|
59
|
+
assert_equal 41.2, @buf.get_double
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
if defined?(Encoding)
|
|
63
|
+
def test_serialize_cstr_converts_encoding_to_utf8
|
|
64
|
+
theta = "hello \xC8".force_encoding("ISO-8859-7")
|
|
65
|
+
ByteBuffer.serialize_cstr(@buf, theta)
|
|
66
|
+
assert_equal "hello \xCE\x98\0", @buf.to_s
|
|
67
|
+
assert_equal Encoding.find('binary'), @buf.to_s.encoding
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def test_serialize_cstr_validates_data_as_utf8
|
|
71
|
+
assert_raises(Encoding::UndefinedConversionError) do
|
|
72
|
+
ByteBuffer.serialize_cstr(@buf, "hello \xFF")
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
else
|
|
76
|
+
def test_serialize_cstr_forces_encoding_to_utf8
|
|
77
|
+
# Unicode snowman (\u2603)
|
|
78
|
+
ByteBuffer.serialize_cstr(@buf, "hello \342\230\203")
|
|
79
|
+
assert_equal "hello \342\230\203\0", @buf.to_s
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def test_serialize_cstr_validates_data_as_utf8
|
|
83
|
+
assert_raises(BSON::InvalidStringEncoding) do
|
|
84
|
+
ByteBuffer.serialize_cstr(@buf, "hello \xFF")
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def test_put_negative_byte
|
|
90
|
+
@buf.put(-1)
|
|
91
|
+
@buf.rewind
|
|
92
|
+
assert_equal 255, @buf.get
|
|
93
|
+
assert_equal "\xFF", @buf.to_s
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def test_put_with_offset
|
|
97
|
+
@buf.put(1)
|
|
98
|
+
@buf.put(2, 0)
|
|
99
|
+
@buf.put(3, 3)
|
|
100
|
+
assert_equal "\x02\x00\x00\x03", @buf.to_s
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def test_put_array_with_offset
|
|
104
|
+
@buf.put(1)
|
|
105
|
+
@buf.put_array([2, 3], 0)
|
|
106
|
+
@buf.put_array([4, 5], 4)
|
|
107
|
+
assert_equal "\x02\x03\x00\x00\x04\x05", @buf.to_s
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def test_put_int_with_offset
|
|
111
|
+
@buf.put(1)
|
|
112
|
+
@buf.put_int(2, 0)
|
|
113
|
+
@buf.put_int(3, 5)
|
|
114
|
+
assert_equal "\x02\x00\x00\x00\x00\x03\x00\x00\x00", @buf.to_s
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def test_put_long_with_offset
|
|
118
|
+
@buf.put(1)
|
|
119
|
+
@buf.put_long(2, 0)
|
|
120
|
+
@buf.put_long(3, 9)
|
|
121
|
+
assert_equal(
|
|
122
|
+
"\x02\x00\x00\x00\x00\x00\x00\x00" +
|
|
123
|
+
"\x00" +
|
|
124
|
+
"\x03\x00\x00\x00\x00\x00\x00\x00",
|
|
125
|
+
@buf.to_s)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def test_put_binary
|
|
129
|
+
@buf.put(1)
|
|
130
|
+
@buf.put_binary("\x02\x03", 0)
|
|
131
|
+
@buf.put_binary("\x04\x05", 4)
|
|
132
|
+
assert_equal "\x02\x03\x00\x00\x04\x05", @buf.to_s
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def test_rewrite
|
|
136
|
+
@buf.put_int(0)
|
|
137
|
+
@buf.rewind
|
|
138
|
+
@buf.put_int(1027)
|
|
139
|
+
assert_equal 4, @buf.length
|
|
140
|
+
@buf.rewind
|
|
141
|
+
assert_equal 1027, @buf.get_int
|
|
142
|
+
assert_equal 4, @buf.position
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def test_prepend_byte_buffer
|
|
146
|
+
@buf.put_int(4)
|
|
147
|
+
new_buf = ByteBuffer.new([5, 0, 0, 0])
|
|
148
|
+
@buf.prepend!(new_buf)
|
|
149
|
+
assert_equal [5, 0, 0, 0, 4, 0, 0, 0], @buf.to_a
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def test_append_byte_buffer
|
|
153
|
+
@buf.put_int(4)
|
|
154
|
+
new_buf = ByteBuffer.new([5, 0, 0, 0])
|
|
155
|
+
@buf.append!(new_buf)
|
|
156
|
+
assert_equal [4, 0, 0, 0, 5, 0, 0, 0], @buf.to_a
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def test_array_as_initial_input
|
|
160
|
+
@buf = ByteBuffer.new([5, 0, 0, 0])
|
|
161
|
+
assert_equal 4, @buf.size
|
|
162
|
+
assert_equal "\x05\x00\x00\x00", @buf.to_s
|
|
163
|
+
assert_equal [5, 0, 0, 0], @buf.to_a
|
|
164
|
+
@buf.put_int(32)
|
|
165
|
+
@buf.rewind
|
|
166
|
+
assert_equal 5, @buf.get_int
|
|
167
|
+
assert_equal 32, @buf.get_int
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def test_binary_string_as_initial_input
|
|
171
|
+
str = "abcd"
|
|
172
|
+
str.force_encoding('binary') if str.respond_to?(:force_encoding)
|
|
173
|
+
@buf = ByteBuffer.new(str)
|
|
174
|
+
assert_equal "abcd", @buf.to_s
|
|
175
|
+
assert_equal [97, 98, 99, 100], @buf.to_a
|
|
176
|
+
@buf.put_int(0)
|
|
177
|
+
assert_equal [97, 98, 99, 100, 0, 0, 0, 0], @buf.to_a
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def test_more
|
|
181
|
+
assert !@buf.more?
|
|
182
|
+
@buf.put_int(5)
|
|
183
|
+
assert !@buf.more?
|
|
184
|
+
@buf.rewind
|
|
185
|
+
assert @buf.more?
|
|
186
|
+
@buf.get_int
|
|
187
|
+
assert !@buf.more?
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
end
|