bson 4.2.2 → 4.12.1
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.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/README.md +25 -7
- data/Rakefile +16 -9
- data/ext/bson/{native-endian.h → bson-endian.h} +5 -99
- data/ext/bson/bson-native.h +125 -0
- data/ext/bson/bytebuf.c +133 -0
- data/ext/bson/endian.c +117 -0
- data/ext/bson/init.c +355 -0
- data/ext/bson/libbson-utf8.c +230 -0
- data/ext/bson/read.c +411 -0
- data/ext/bson/util.c +95 -0
- data/ext/bson/write.c +680 -0
- data/lib/bson.rb +6 -3
- data/lib/bson/active_support.rb +17 -0
- data/lib/bson/array.rb +57 -17
- data/lib/bson/binary.rb +185 -13
- data/lib/bson/boolean.rb +12 -3
- data/lib/bson/code.rb +16 -2
- data/lib/bson/code_with_scope.rb +32 -5
- data/lib/bson/config.rb +1 -1
- data/lib/bson/date.rb +12 -2
- data/lib/bson/date_time.rb +2 -2
- data/lib/bson/db_pointer.rb +110 -0
- data/lib/bson/decimal128.rb +17 -3
- data/lib/bson/decimal128/builder.rb +1 -1
- data/lib/bson/document.rb +152 -5
- data/lib/bson/environment.rb +2 -1
- data/lib/bson/error.rb +27 -0
- data/lib/bson/ext_json.rb +383 -0
- data/lib/bson/false_class.rb +1 -1
- data/lib/bson/float.rb +48 -2
- data/lib/bson/hash.rb +68 -17
- data/lib/bson/int32.rb +52 -13
- data/lib/bson/int64.rb +59 -15
- data/lib/bson/integer.rb +36 -2
- data/lib/bson/json.rb +1 -1
- data/lib/bson/max_key.rb +13 -1
- data/lib/bson/min_key.rb +13 -1
- data/lib/bson/nil_class.rb +4 -2
- data/lib/bson/object.rb +28 -1
- data/lib/bson/object_id.rb +16 -2
- data/lib/bson/open_struct.rb +1 -1
- data/lib/bson/regexp.rb +27 -4
- data/lib/bson/registry.rb +3 -3
- data/lib/bson/specialized.rb +4 -2
- data/lib/bson/string.rb +5 -3
- data/lib/bson/symbol.rb +99 -7
- data/lib/bson/time.rb +63 -4
- data/lib/bson/time_with_zone.rb +54 -0
- data/lib/bson/timestamp.rb +44 -6
- data/lib/bson/true_class.rb +1 -1
- data/lib/bson/undefined.rb +12 -1
- data/lib/bson/version.rb +2 -2
- data/spec/bson/array_spec.rb +18 -1
- data/spec/bson/binary_spec.rb +100 -3
- data/spec/bson/binary_uuid_spec.rb +189 -0
- data/spec/bson/boolean_spec.rb +1 -1
- data/spec/bson/byte_buffer_read_spec.rb +197 -0
- data/spec/bson/byte_buffer_spec.rb +121 -381
- data/spec/bson/byte_buffer_write_spec.rb +854 -0
- data/spec/bson/code_spec.rb +1 -1
- data/spec/bson/code_with_scope_spec.rb +1 -1
- data/spec/bson/date_spec.rb +1 -1
- data/spec/bson/date_time_spec.rb +54 -1
- data/spec/bson/decimal128_spec.rb +35 -35
- data/spec/bson/document_as_spec.rb +46 -0
- data/spec/bson/document_spec.rb +197 -30
- data/spec/bson/ext_json_parse_spec.rb +308 -0
- data/spec/bson/false_class_spec.rb +1 -1
- data/spec/bson/float_spec.rb +37 -1
- data/spec/bson/hash_as_spec.rb +57 -0
- data/spec/bson/hash_spec.rb +209 -1
- data/spec/bson/int32_spec.rb +180 -6
- data/spec/bson/int64_spec.rb +199 -6
- data/spec/bson/integer_spec.rb +29 -3
- data/spec/bson/json_spec.rb +1 -1
- data/spec/bson/max_key_spec.rb +1 -1
- data/spec/bson/min_key_spec.rb +1 -1
- data/spec/bson/nil_class_spec.rb +1 -1
- data/spec/bson/object_id_spec.rb +1 -1
- data/spec/bson/object_spec.rb +1 -1
- data/spec/bson/open_struct_spec.rb +1 -1
- data/spec/bson/raw_spec.rb +34 -2
- data/spec/bson/regexp_spec.rb +1 -1
- data/spec/bson/registry_spec.rb +1 -1
- data/spec/bson/string_spec.rb +19 -1
- data/spec/bson/symbol_raw_spec.rb +45 -0
- data/spec/bson/symbol_spec.rb +63 -3
- data/spec/bson/time_spec.rb +205 -2
- data/spec/bson/time_with_zone_spec.rb +68 -0
- data/spec/bson/timestamp_spec.rb +56 -1
- data/spec/bson/true_class_spec.rb +1 -1
- data/spec/bson/undefined_spec.rb +1 -1
- data/spec/bson_spec.rb +1 -1
- data/spec/{support → runners}/common_driver.rb +1 -1
- data/spec/runners/corpus.rb +185 -0
- data/spec/{support/corpus.rb → runners/corpus_legacy.rb} +41 -59
- data/spec/spec_helper.rb +40 -3
- data/spec/{bson/driver_bson_spec.rb → spec_tests/common_driver_spec.rb} +1 -0
- data/spec/{bson/corpus_spec.rb → spec_tests/corpus_legacy_spec.rb} +10 -7
- data/spec/spec_tests/corpus_spec.rb +124 -0
- data/spec/spec_tests/data/corpus/README.md +15 -0
- data/spec/spec_tests/data/corpus/array.json +49 -0
- data/spec/spec_tests/data/corpus/binary.json +113 -0
- data/spec/spec_tests/data/corpus/boolean.json +27 -0
- data/spec/spec_tests/data/corpus/code.json +67 -0
- data/spec/spec_tests/data/corpus/code_w_scope.json +78 -0
- data/spec/spec_tests/data/corpus/datetime.json +42 -0
- data/spec/spec_tests/data/corpus/dbpointer.json +56 -0
- data/spec/spec_tests/data/corpus/dbref.json +31 -0
- data/spec/spec_tests/data/corpus/decimal128-1.json +317 -0
- data/spec/spec_tests/data/corpus/decimal128-2.json +793 -0
- data/spec/spec_tests/data/corpus/decimal128-3.json +1771 -0
- data/spec/spec_tests/data/corpus/decimal128-4.json +117 -0
- data/spec/spec_tests/data/corpus/decimal128-5.json +402 -0
- data/spec/spec_tests/data/corpus/decimal128-6.json +119 -0
- data/spec/spec_tests/data/corpus/decimal128-7.json +323 -0
- data/spec/spec_tests/data/corpus/document.json +36 -0
- data/spec/spec_tests/data/corpus/double.json +87 -0
- data/spec/spec_tests/data/corpus/int32.json +43 -0
- data/spec/spec_tests/data/corpus/int64.json +43 -0
- data/spec/spec_tests/data/corpus/maxkey.json +12 -0
- data/spec/spec_tests/data/corpus/minkey.json +12 -0
- data/spec/spec_tests/data/corpus/multi-type-deprecated.json +15 -0
- data/spec/spec_tests/data/corpus/multi-type.json +11 -0
- data/spec/spec_tests/data/corpus/null.json +12 -0
- data/spec/spec_tests/data/corpus/oid.json +28 -0
- data/spec/spec_tests/data/corpus/regex.json +65 -0
- data/spec/spec_tests/data/corpus/string.json +72 -0
- data/spec/spec_tests/data/corpus/symbol.json +80 -0
- data/spec/spec_tests/data/corpus/timestamp.json +34 -0
- data/spec/spec_tests/data/corpus/top.json +236 -0
- data/spec/spec_tests/data/corpus/undefined.json +15 -0
- data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/array.json +8 -2
- data/spec/{support/corpus-tests/failures → spec_tests/data/corpus_legacy}/binary.json +0 -0
- data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/boolean.json +0 -0
- data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/code.json +1 -1
- data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/code_w_scope.json +1 -1
- data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/document.json +1 -1
- data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/double.json +1 -1
- data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/failures/datetime.json +0 -0
- data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/failures/dbpointer.json +0 -0
- data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/failures/int64.json +0 -0
- data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/failures/symbol.json +0 -0
- data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/int32.json +1 -1
- data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/maxkey.json +1 -1
- data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/minkey.json +1 -1
- data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/null.json +1 -1
- data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/oid.json +0 -0
- data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/regex.json +1 -1
- data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/string.json +0 -0
- data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/timestamp.json +1 -1
- data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/top.json +0 -0
- data/spec/{support/corpus-tests/failures → spec_tests/data/corpus_legacy}/undefined.json +0 -0
- data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-1.json +0 -0
- data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-2.json +0 -0
- data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-3.json +0 -0
- data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-4.json +0 -0
- data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-5.json +0 -0
- data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-6.json +0 -0
- data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-7.json +0 -0
- data/spec/support/shared_examples.rb +3 -5
- data/spec/support/spec_config.rb +16 -0
- data/spec/support/utils.rb +10 -0
- metadata +227 -124
- metadata.gz.sig +0 -0
- data/ext/bson/bson_native.c +0 -762
@@ -0,0 +1,854 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe BSON::ByteBuffer do
|
4
|
+
|
5
|
+
let(:buffer) do
|
6
|
+
described_class.new
|
7
|
+
end
|
8
|
+
|
9
|
+
shared_examples_for 'does not write' do
|
10
|
+
it 'raises ArgumentError' do
|
11
|
+
expect do
|
12
|
+
modified
|
13
|
+
end.to raise_error(ArgumentError)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'does not change write position' do
|
17
|
+
expect do
|
18
|
+
modified
|
19
|
+
end.to raise_error(ArgumentError)
|
20
|
+
|
21
|
+
expect(buffer.write_position).to eq(0)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#put_byte' do
|
26
|
+
|
27
|
+
let(:modified) do
|
28
|
+
buffer.put_byte(BSON::Int32::BSON_TYPE)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'appends the byte to the byte buffer' do
|
32
|
+
expect(modified.to_s).to eq(BSON::Int32::BSON_TYPE.chr)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'increments the write position by 1' do
|
36
|
+
expect(modified.write_position).to eq(1)
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'when it receives a numeric value' do
|
40
|
+
it 'raises the ArgumentError exception' do
|
41
|
+
expect{buffer.put_byte(1)}.to raise_error(ArgumentError)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'when it receives a nil value' do
|
46
|
+
it 'raises the ArgumentError exception' do
|
47
|
+
expect{buffer.put_byte(nil)}.to raise_error(ArgumentError)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'when given a string of length > 1' do
|
52
|
+
|
53
|
+
let(:modified) do
|
54
|
+
buffer.put_byte('xx')
|
55
|
+
end
|
56
|
+
|
57
|
+
it_behaves_like 'does not write'
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'when given a string of length 0' do
|
61
|
+
|
62
|
+
let(:modified) do
|
63
|
+
buffer.put_byte('')
|
64
|
+
end
|
65
|
+
|
66
|
+
it_behaves_like 'does not write'
|
67
|
+
end
|
68
|
+
|
69
|
+
context 'when byte is not valid utf-8' do
|
70
|
+
let(:string) do
|
71
|
+
Utils.make_byte_string([254]).freeze
|
72
|
+
end
|
73
|
+
|
74
|
+
let(:modified) do
|
75
|
+
buffer.put_byte(string)
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'writes the byte' do
|
79
|
+
expect(modified.to_s).to eq(string)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe '#put_bytes' do
|
85
|
+
|
86
|
+
let(:modified) do
|
87
|
+
buffer.put_bytes(BSON::Int32::BSON_TYPE)
|
88
|
+
buffer
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'increments the write position by 1' do
|
92
|
+
expect(modified.write_position).to eq(1)
|
93
|
+
end
|
94
|
+
|
95
|
+
context 'when it receives a numeric value' do
|
96
|
+
it 'raises the ArgumentError exception' do
|
97
|
+
expect{buffer.put_bytes(1)}.to raise_error(ArgumentError)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
context 'when it receives a nil value' do
|
102
|
+
it 'raises the ArgumentError exception' do
|
103
|
+
expect{buffer.put_bytes(nil)}.to raise_error(ArgumentError)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
context 'when given a string with null bytes' do
|
108
|
+
let(:byte_str) { [0, 239, 254, 0].map(&:chr).join }
|
109
|
+
|
110
|
+
let(:modified) do
|
111
|
+
buffer.put_bytes(byte_str)
|
112
|
+
end
|
113
|
+
|
114
|
+
before do
|
115
|
+
expect(buffer.write_position).to eq(0)
|
116
|
+
expect(byte_str.length).to eq(4)
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'writes the string' do
|
120
|
+
expect(modified.write_position).to eq(4)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context 'when bytes are not valid utf-8' do
|
125
|
+
let(:string) do
|
126
|
+
Utils.make_byte_string([254, 0, 255]).freeze
|
127
|
+
end
|
128
|
+
|
129
|
+
let(:modified) do
|
130
|
+
buffer.put_bytes(string)
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'writes the bytes' do
|
134
|
+
expect(modified.to_s).to eq(string)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
shared_examples_for 'bson string writer' do
|
140
|
+
|
141
|
+
context 'given empty string' do
|
142
|
+
let(:modified) do
|
143
|
+
buffer.put_string('')
|
144
|
+
end
|
145
|
+
|
146
|
+
it 'writes length and null terminator' do
|
147
|
+
expect(modified.write_position).to eq(5)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
context 'when string is not valid utf-8 in utf-8 encoding' do
|
152
|
+
let(:string) do
|
153
|
+
Utils.make_byte_string([254, 253, 255], 'utf-8')
|
154
|
+
end
|
155
|
+
|
156
|
+
before do
|
157
|
+
expect(string.encoding.name).to eq('UTF-8')
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'raises EncodingError' do
|
161
|
+
# Precise exception classes and messages differ between MRI and JRuby
|
162
|
+
expect do
|
163
|
+
modified
|
164
|
+
end.to raise_error(EncodingError)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
context 'when string is in binary encoding and cannot be encoded in utf-8' do
|
169
|
+
let(:string) do
|
170
|
+
Utils.make_byte_string([254, 253, 255], 'binary')
|
171
|
+
end
|
172
|
+
|
173
|
+
before do
|
174
|
+
expect(string.encoding.name).to eq('ASCII-8BIT')
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'raises Encoding::UndefinedConversionError' do
|
178
|
+
expect do
|
179
|
+
modified
|
180
|
+
end.to raise_error(Encoding::UndefinedConversionError, /from ASCII-8BIT to UTF-8/)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
describe '#put_string' do
|
186
|
+
|
187
|
+
let(:modified) do
|
188
|
+
buffer.put_string(string)
|
189
|
+
end
|
190
|
+
|
191
|
+
it_behaves_like 'bson string writer'
|
192
|
+
|
193
|
+
context 'when the buffer does not need to be expanded' do
|
194
|
+
|
195
|
+
context 'when the string is UTF-8' do
|
196
|
+
|
197
|
+
let!(:modified) do
|
198
|
+
buffer.put_string('testing')
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'appends the string to the byte buffer' do
|
202
|
+
expect(modified.to_s).to eq("#{8.to_bson.to_s}testing#{BSON::NULL_BYTE}")
|
203
|
+
end
|
204
|
+
|
205
|
+
it 'increments the write position by length + 5' do
|
206
|
+
expect(modified.write_position).to eq(12)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
context 'when the buffer needs to be expanded' do
|
212
|
+
|
213
|
+
let(:string) do
|
214
|
+
300.times.inject(""){ |s, i| s << "#{i}" }
|
215
|
+
end
|
216
|
+
|
217
|
+
context 'when no bytes exist in the buffer' do
|
218
|
+
|
219
|
+
let!(:modified) do
|
220
|
+
buffer.put_string(string)
|
221
|
+
end
|
222
|
+
|
223
|
+
it 'appends the string to the byte buffer' do
|
224
|
+
expect(modified.to_s).to eq("#{(string.bytesize + 1).to_bson.to_s}#{string}#{BSON::NULL_BYTE}")
|
225
|
+
end
|
226
|
+
|
227
|
+
it 'increments the write position by length + 5' do
|
228
|
+
expect(modified.write_position).to eq(string.bytesize + 5)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
context 'when bytes exist in the buffer' do
|
233
|
+
|
234
|
+
let!(:modified) do
|
235
|
+
buffer.put_int32(4).put_string(string)
|
236
|
+
end
|
237
|
+
|
238
|
+
it 'appends the string to the byte buffer' do
|
239
|
+
expect(modified.to_s).to eq(
|
240
|
+
"#{[ 4 ].pack(BSON::Int32::PACK)}#{(string.bytesize + 1).to_bson.to_s}#{string}#{BSON::NULL_BYTE}"
|
241
|
+
)
|
242
|
+
end
|
243
|
+
|
244
|
+
it 'increments the write position by length + 5' do
|
245
|
+
expect(modified.write_position).to eq(string.bytesize + 9)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
context 'when string is in an encoding other than utf-8' do
|
251
|
+
let(:string) do
|
252
|
+
# "\xfe"
|
253
|
+
Utils.make_byte_string([254], 'iso-8859-1')
|
254
|
+
end
|
255
|
+
|
256
|
+
let(:expected) do
|
257
|
+
# \xc3\xbe == \u00fe
|
258
|
+
Utils.make_byte_string([3, 0, 0, 0, 0xc3, 0xbe, 0])
|
259
|
+
end
|
260
|
+
|
261
|
+
it 'is written as utf-8' do
|
262
|
+
expect(modified.to_s).to eq(expected)
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
describe '#put_cstring' do
|
268
|
+
|
269
|
+
let(:modified) do
|
270
|
+
buffer.put_cstring(string)
|
271
|
+
end
|
272
|
+
|
273
|
+
it_behaves_like 'bson string writer'
|
274
|
+
|
275
|
+
context 'when argument is a string' do
|
276
|
+
context 'when the string is valid' do
|
277
|
+
|
278
|
+
let!(:modified) do
|
279
|
+
buffer.put_cstring('testing')
|
280
|
+
end
|
281
|
+
|
282
|
+
it 'appends the string plus null byte to the byte buffer' do
|
283
|
+
expect(modified.to_s).to eq("testing#{BSON::NULL_BYTE}")
|
284
|
+
end
|
285
|
+
|
286
|
+
it 'increments the write position by the length + 1' do
|
287
|
+
expect(modified.write_position).to eq(8)
|
288
|
+
end
|
289
|
+
|
290
|
+
it 'mutates receiver' do
|
291
|
+
modified
|
292
|
+
expect(buffer.write_position).to eq(8)
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
context "when the string contains a null byte" do
|
297
|
+
|
298
|
+
let(:string) do
|
299
|
+
"test#{BSON::NULL_BYTE}ing"
|
300
|
+
end
|
301
|
+
|
302
|
+
it 'raises ArgumentError' do
|
303
|
+
expect {
|
304
|
+
modified
|
305
|
+
}.to raise_error(ArgumentError, /String .* contains null bytes/)
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
context 'when string is in an encoding other than utf-8' do
|
310
|
+
let(:string) do
|
311
|
+
# "\xfe"
|
312
|
+
Utils.make_byte_string([254], 'iso-8859-1')
|
313
|
+
end
|
314
|
+
|
315
|
+
let(:expected) do
|
316
|
+
# \xc3\xbe == \u00fe
|
317
|
+
# No length prefix
|
318
|
+
Utils.make_byte_string([0xc3, 0xbe, 0])
|
319
|
+
end
|
320
|
+
|
321
|
+
it 'is written as utf-8' do
|
322
|
+
expect(modified.to_s).to eq(expected)
|
323
|
+
end
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
context 'when argument is a symbol' do
|
328
|
+
let(:modified) do
|
329
|
+
buffer.put_cstring(:testing)
|
330
|
+
end
|
331
|
+
|
332
|
+
it 'writes' do
|
333
|
+
expect(modified.to_s).to eq("testing#{BSON::NULL_BYTE}")
|
334
|
+
end
|
335
|
+
|
336
|
+
it 'increments the write position by the length + 1' do
|
337
|
+
expect(modified.write_position).to eq(8)
|
338
|
+
end
|
339
|
+
|
340
|
+
it 'mutates receiver' do
|
341
|
+
modified
|
342
|
+
expect(buffer.write_position).to eq(8)
|
343
|
+
end
|
344
|
+
|
345
|
+
context 'when symbol includes a null byte' do
|
346
|
+
let(:modified) do
|
347
|
+
buffer.put_cstring(:"tes\x00ing")
|
348
|
+
end
|
349
|
+
|
350
|
+
it 'raises ArgumentError' do
|
351
|
+
expect {
|
352
|
+
modified
|
353
|
+
}.to raise_error(ArgumentError, /String .* contains null bytes/)
|
354
|
+
end
|
355
|
+
|
356
|
+
it 'does not change write position' do
|
357
|
+
begin
|
358
|
+
buffer.put_cstring(:"tes\x00ing")
|
359
|
+
rescue ArgumentError
|
360
|
+
end
|
361
|
+
|
362
|
+
expect(buffer.write_position).to eq(0)
|
363
|
+
end
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
context 'when argument is a Fixnum' do
|
368
|
+
let(:modified) do
|
369
|
+
buffer.put_cstring(1234)
|
370
|
+
end
|
371
|
+
|
372
|
+
it 'writes' do
|
373
|
+
expect(modified.to_s).to eq("1234#{BSON::NULL_BYTE}")
|
374
|
+
end
|
375
|
+
|
376
|
+
it 'increments the write position by the length + 1' do
|
377
|
+
expect(modified.write_position).to eq(5)
|
378
|
+
end
|
379
|
+
end
|
380
|
+
|
381
|
+
context 'when argument is of an unsupported type' do
|
382
|
+
let(:modified) do
|
383
|
+
buffer.put_cstring(1234.0)
|
384
|
+
end
|
385
|
+
|
386
|
+
it 'raises TypeError' do
|
387
|
+
expect do
|
388
|
+
modified
|
389
|
+
end.to raise_error(TypeError, /Invalid type for put_cstring/)
|
390
|
+
end
|
391
|
+
|
392
|
+
it 'does not change write position' do
|
393
|
+
begin
|
394
|
+
buffer.put_cstring(1234.0)
|
395
|
+
rescue TypeError
|
396
|
+
end
|
397
|
+
|
398
|
+
expect(buffer.write_position).to eq(0)
|
399
|
+
end
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
403
|
+
describe '#put_symbol' do
|
404
|
+
context 'normal symbol' do
|
405
|
+
let(:modified) do
|
406
|
+
buffer.put_symbol(:hello)
|
407
|
+
end
|
408
|
+
|
409
|
+
it 'writes the symbol as string' do
|
410
|
+
expect(modified.to_s).to eq("\x06\x00\x00\x00hello\x00")
|
411
|
+
end
|
412
|
+
|
413
|
+
it 'advances write position' do
|
414
|
+
# 4 byte length + 5 byte string + null byte
|
415
|
+
expect(modified.write_position).to eq(10)
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
419
|
+
context 'symbol with null byte' do
|
420
|
+
let(:modified) do
|
421
|
+
buffer.put_symbol(:"he\x00lo")
|
422
|
+
end
|
423
|
+
|
424
|
+
it 'writes the symbol as string' do
|
425
|
+
expect(modified.to_s).to eq("\x06\x00\x00\x00he\x00lo\x00")
|
426
|
+
end
|
427
|
+
|
428
|
+
it 'advances write position' do
|
429
|
+
# 4 byte length + 5 byte string + null byte
|
430
|
+
expect(modified.write_position).to eq(10)
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
context 'when symbol is not valid utf-8' do
|
435
|
+
let(:symbol) do
|
436
|
+
Utils.make_byte_string([254, 0, 255]).to_sym
|
437
|
+
end
|
438
|
+
|
439
|
+
let(:modified) do
|
440
|
+
buffer.put_symbol(symbol)
|
441
|
+
end
|
442
|
+
|
443
|
+
it 'raises EncodingError' do
|
444
|
+
# Precise exception classes and messages differ between MRI and JRuby
|
445
|
+
expect do
|
446
|
+
modified
|
447
|
+
end.to raise_error(EncodingError)
|
448
|
+
end
|
449
|
+
end
|
450
|
+
end
|
451
|
+
|
452
|
+
describe '#put_double' do
|
453
|
+
|
454
|
+
let(:modified) do
|
455
|
+
buffer.put_double(1.2332)
|
456
|
+
end
|
457
|
+
|
458
|
+
it 'appends the double to the buffer' do
|
459
|
+
expect(modified.to_s).to eq([ 1.2332 ].pack(Float::PACK))
|
460
|
+
end
|
461
|
+
|
462
|
+
it 'increments the write position by 8' do
|
463
|
+
expect(modified.write_position).to eq(8)
|
464
|
+
end
|
465
|
+
|
466
|
+
context 'when argument is an integer' do
|
467
|
+
|
468
|
+
let(:modified) do
|
469
|
+
buffer.put_double(3)
|
470
|
+
end
|
471
|
+
|
472
|
+
it 'writes a double' do
|
473
|
+
expect(modified.to_s).to eq([ 3 ].pack(Float::PACK))
|
474
|
+
end
|
475
|
+
|
476
|
+
it 'increments the write position by 8' do
|
477
|
+
expect(modified.write_position).to eq(8)
|
478
|
+
end
|
479
|
+
end
|
480
|
+
|
481
|
+
context 'when argument is a BigNum' do
|
482
|
+
let(:value) { 123456789012345678901234567890 }
|
483
|
+
|
484
|
+
let(:modified) do
|
485
|
+
buffer.put_double(value)
|
486
|
+
end
|
487
|
+
|
488
|
+
let(:actual) do
|
489
|
+
described_class.new(modified.to_s).get_double
|
490
|
+
end
|
491
|
+
|
492
|
+
it 'writes a double' do
|
493
|
+
expect(actual).to be_within(1).of(value)
|
494
|
+
end
|
495
|
+
|
496
|
+
it 'increments the write position by 8' do
|
497
|
+
expect(modified.write_position).to eq(8)
|
498
|
+
end
|
499
|
+
end
|
500
|
+
|
501
|
+
context 'when argument is a string' do
|
502
|
+
|
503
|
+
let(:modified) do
|
504
|
+
buffer.put_double("hello")
|
505
|
+
end
|
506
|
+
|
507
|
+
it 'raises TypeError' do
|
508
|
+
expect do
|
509
|
+
modified
|
510
|
+
end.to raise_error(TypeError, /no implicit conversion to float from string|ClassCastException:.*RubyString cannot be cast to.*RubyFloat/)
|
511
|
+
expect(buffer.write_position).to eq(0)
|
512
|
+
end
|
513
|
+
end
|
514
|
+
end
|
515
|
+
|
516
|
+
describe '#put_int32' do
|
517
|
+
|
518
|
+
context 'when the integer is 32 bit' do
|
519
|
+
|
520
|
+
context 'when the integer is positive' do
|
521
|
+
|
522
|
+
let!(:modified) do
|
523
|
+
buffer.put_int32(Integer::MAX_32BIT - 1)
|
524
|
+
end
|
525
|
+
|
526
|
+
let(:expected) do
|
527
|
+
[ Integer::MAX_32BIT - 1 ].pack(BSON::Int32::PACK)
|
528
|
+
end
|
529
|
+
|
530
|
+
it 'appends the int32 to the byte buffer' do
|
531
|
+
expect(modified.to_s).to eq(expected)
|
532
|
+
end
|
533
|
+
|
534
|
+
it 'increments the write position by 4' do
|
535
|
+
expect(modified.write_position).to eq(4)
|
536
|
+
end
|
537
|
+
end
|
538
|
+
|
539
|
+
context 'when the integer is negative' do
|
540
|
+
|
541
|
+
let!(:modified) do
|
542
|
+
buffer.put_int32(Integer::MIN_32BIT + 1)
|
543
|
+
end
|
544
|
+
|
545
|
+
let(:expected) do
|
546
|
+
[ Integer::MIN_32BIT + 1 ].pack(BSON::Int32::PACK)
|
547
|
+
end
|
548
|
+
|
549
|
+
it 'appends the int32 to the byte buffer' do
|
550
|
+
expect(modified.to_s).to eq(expected)
|
551
|
+
end
|
552
|
+
|
553
|
+
it 'increments the write position by 4' do
|
554
|
+
expect(modified.write_position).to eq(4)
|
555
|
+
end
|
556
|
+
end
|
557
|
+
|
558
|
+
context 'when the integer is not 32 bit' do
|
559
|
+
|
560
|
+
it 'raises an exception' do
|
561
|
+
expect {
|
562
|
+
buffer.put_int32(Integer::MAX_64BIT - 1)
|
563
|
+
}.to raise_error(RangeError)
|
564
|
+
end
|
565
|
+
end
|
566
|
+
end
|
567
|
+
|
568
|
+
context 'when argument is a float' do
|
569
|
+
|
570
|
+
let(:modified) do
|
571
|
+
buffer.put_int32(4.934)
|
572
|
+
end
|
573
|
+
|
574
|
+
let(:expected) do
|
575
|
+
[ 4 ].pack(BSON::Int32::PACK)
|
576
|
+
end
|
577
|
+
|
578
|
+
it 'appends the int32 to the byte buffer' do
|
579
|
+
expect(modified.to_s).to eq(expected)
|
580
|
+
end
|
581
|
+
|
582
|
+
it 'increments the write position by 4' do
|
583
|
+
expect(modified.write_position).to eq(4)
|
584
|
+
end
|
585
|
+
end
|
586
|
+
end
|
587
|
+
|
588
|
+
describe '#put_uint32' do
|
589
|
+
context 'when argument is a float' do
|
590
|
+
it 'raises an Argument Error' do
|
591
|
+
expect{ buffer.put_uint32(4.934) }.to raise_error(ArgumentError, "put_uint32: incorrect type: float, expected: integer")
|
592
|
+
end
|
593
|
+
end
|
594
|
+
|
595
|
+
context 'when number is in range' do
|
596
|
+
let(:modified) do
|
597
|
+
buffer.put_uint32(5)
|
598
|
+
end
|
599
|
+
|
600
|
+
it 'returns gets the correct number from the buffer' do
|
601
|
+
expect(modified.get_uint32).to eq(5)
|
602
|
+
end
|
603
|
+
|
604
|
+
it 'returns the length of the buffer' do
|
605
|
+
expect(modified.length).to eq(4)
|
606
|
+
end
|
607
|
+
end
|
608
|
+
|
609
|
+
context 'when number is 0' do
|
610
|
+
let(:modified) do
|
611
|
+
buffer.put_uint32(0)
|
612
|
+
end
|
613
|
+
|
614
|
+
it 'returns gets the correct number from the buffer' do
|
615
|
+
expect(modified.get_uint32).to eq(0)
|
616
|
+
end
|
617
|
+
|
618
|
+
it 'returns the length of the buffer' do
|
619
|
+
expect(modified.length).to eq(4)
|
620
|
+
end
|
621
|
+
end
|
622
|
+
|
623
|
+
context 'when number doesn\'t fit in signed int32' do
|
624
|
+
let(:modified) do
|
625
|
+
buffer.put_uint32(4294967295)
|
626
|
+
end
|
627
|
+
|
628
|
+
let(:expected) do
|
629
|
+
[ 4294967295 ].pack(BSON::Int32::PACK)
|
630
|
+
end
|
631
|
+
|
632
|
+
it 'appends the int32 to the byte buffer' do
|
633
|
+
expect(modified.to_s).to eq(expected)
|
634
|
+
end
|
635
|
+
|
636
|
+
it 'get returns correct number' do
|
637
|
+
expect(modified.get_uint32).to eq(4294967295)
|
638
|
+
end
|
639
|
+
|
640
|
+
it 'returns the length of the buffer' do
|
641
|
+
expect(modified.length).to eq(4)
|
642
|
+
end
|
643
|
+
end
|
644
|
+
|
645
|
+
context 'when number is 2^31' do
|
646
|
+
let(:modified) do
|
647
|
+
buffer.put_uint32(2147483648)
|
648
|
+
end
|
649
|
+
|
650
|
+
it 'returns gets the correct number from the buffer' do
|
651
|
+
expect(modified.get_uint32).to eq(2147483648)
|
652
|
+
end
|
653
|
+
|
654
|
+
it 'returns the length of the buffer' do
|
655
|
+
expect(modified.length).to eq(4)
|
656
|
+
end
|
657
|
+
end
|
658
|
+
|
659
|
+
context 'when number is 2^31-1' do
|
660
|
+
let(:modified) do
|
661
|
+
buffer.put_uint32(2147483647)
|
662
|
+
end
|
663
|
+
|
664
|
+
it 'returns gets the correct number from the buffer' do
|
665
|
+
expect(modified.get_uint32).to eq(2147483647)
|
666
|
+
end
|
667
|
+
|
668
|
+
it 'returns the length of the buffer' do
|
669
|
+
expect(modified.length).to eq(4)
|
670
|
+
end
|
671
|
+
end
|
672
|
+
|
673
|
+
context 'when number is not in range' do
|
674
|
+
it 'raises error on out of top range' do
|
675
|
+
expect{ buffer.put_uint32(4294967296) }.to raise_error(RangeError, "Number 4294967296 is out of range [0, 2^32)")
|
676
|
+
end
|
677
|
+
|
678
|
+
it 'raises error on out of bottom range' do
|
679
|
+
expect{ buffer.put_uint32(-1) }.to raise_error(RangeError, "Number -1 is out of range [0, 2^32)")
|
680
|
+
end
|
681
|
+
end
|
682
|
+
end
|
683
|
+
|
684
|
+
describe '#put_int64' do
|
685
|
+
|
686
|
+
context 'when the integer is 64 bit' do
|
687
|
+
|
688
|
+
context 'when the integer is positive' do
|
689
|
+
|
690
|
+
let!(:modified) do
|
691
|
+
buffer.put_int64(Integer::MAX_64BIT - 1)
|
692
|
+
end
|
693
|
+
|
694
|
+
let(:expected) do
|
695
|
+
[ Integer::MAX_64BIT - 1 ].pack(BSON::Int64::PACK)
|
696
|
+
end
|
697
|
+
|
698
|
+
it 'appends the int64 to the byte buffer' do
|
699
|
+
expect(modified.to_s).to eq(expected)
|
700
|
+
end
|
701
|
+
|
702
|
+
it 'increments the write position by 8' do
|
703
|
+
expect(modified.write_position).to eq(8)
|
704
|
+
end
|
705
|
+
end
|
706
|
+
|
707
|
+
context 'when the integer is negative' do
|
708
|
+
|
709
|
+
let!(:modified) do
|
710
|
+
buffer.put_int64(Integer::MIN_64BIT + 1)
|
711
|
+
end
|
712
|
+
|
713
|
+
let(:expected) do
|
714
|
+
[ Integer::MIN_64BIT + 1 ].pack(BSON::Int64::PACK)
|
715
|
+
end
|
716
|
+
|
717
|
+
it 'appends the int64 to the byte buffer' do
|
718
|
+
expect(modified.to_s).to eq(expected)
|
719
|
+
end
|
720
|
+
|
721
|
+
it 'increments the write position by 8' do
|
722
|
+
expect(modified.write_position).to eq(8)
|
723
|
+
end
|
724
|
+
end
|
725
|
+
|
726
|
+
context 'when the integer is larger than 64 bit' do
|
727
|
+
|
728
|
+
it 'raises an exception' do
|
729
|
+
expect {
|
730
|
+
buffer.put_int64(Integer::MAX_64BIT + 1)
|
731
|
+
}.to raise_error(RangeError)
|
732
|
+
end
|
733
|
+
end
|
734
|
+
end
|
735
|
+
|
736
|
+
context 'when integer fits in 32 bits' do
|
737
|
+
let(:modified) do
|
738
|
+
buffer.put_int64(1)
|
739
|
+
end
|
740
|
+
|
741
|
+
it 'increments the write position by 8' do
|
742
|
+
expect(modified.write_position).to eq(8)
|
743
|
+
end
|
744
|
+
end
|
745
|
+
|
746
|
+
context 'when argument is a float' do
|
747
|
+
|
748
|
+
let(:modified) do
|
749
|
+
buffer.put_int64(4.934)
|
750
|
+
end
|
751
|
+
|
752
|
+
let(:expected) do
|
753
|
+
[ 4 ].pack(BSON::Int64::PACK)
|
754
|
+
end
|
755
|
+
|
756
|
+
it 'appends the int64 to the byte buffer' do
|
757
|
+
expect(modified.to_s).to eq(expected)
|
758
|
+
end
|
759
|
+
|
760
|
+
it 'increments the write position by 8' do
|
761
|
+
expect(modified.write_position).to eq(8)
|
762
|
+
end
|
763
|
+
end
|
764
|
+
end
|
765
|
+
|
766
|
+
describe '#replace_int32' do
|
767
|
+
|
768
|
+
let(:exp_0) do
|
769
|
+
[ 0 ].pack(BSON::Int32::PACK)
|
770
|
+
end
|
771
|
+
|
772
|
+
let(:exp_first) do
|
773
|
+
[ 5 ].pack(BSON::Int32::PACK)
|
774
|
+
end
|
775
|
+
|
776
|
+
let(:exp_second) do
|
777
|
+
[ 4 ].pack(BSON::Int32::PACK)
|
778
|
+
end
|
779
|
+
|
780
|
+
let(:exp_42) do
|
781
|
+
[ 42 ].pack(BSON::Int32::PACK)
|
782
|
+
end
|
783
|
+
|
784
|
+
let(:modified) do
|
785
|
+
buffer.replace_int32(0, 5)
|
786
|
+
end
|
787
|
+
|
788
|
+
context 'when there is sufficient data in buffer' do
|
789
|
+
|
790
|
+
before do
|
791
|
+
buffer.put_int32(0).put_int32(4)
|
792
|
+
end
|
793
|
+
|
794
|
+
it 'replaces the int32 at the location' do
|
795
|
+
expect(modified.to_s).to eq("#{exp_first}#{exp_second}")
|
796
|
+
end
|
797
|
+
|
798
|
+
context 'when the position is negative' do
|
799
|
+
|
800
|
+
let(:modified) do
|
801
|
+
buffer.replace_int32(-1, 5)
|
802
|
+
end
|
803
|
+
|
804
|
+
it 'raises ArgumentError' do
|
805
|
+
expect do
|
806
|
+
modified
|
807
|
+
end.to raise_error(ArgumentError, /Position.*cannot be negative/)
|
808
|
+
end
|
809
|
+
end
|
810
|
+
|
811
|
+
context 'when the position is 4 bytes prior to write position' do
|
812
|
+
|
813
|
+
let(:modified) do
|
814
|
+
buffer.replace_int32(4, 42)
|
815
|
+
end
|
816
|
+
|
817
|
+
it 'replaces the int32 at the location' do
|
818
|
+
expect(modified.to_s).to eq("#{exp_0}#{exp_42}")
|
819
|
+
end
|
820
|
+
end
|
821
|
+
|
822
|
+
context 'when the position exceeds allowed range' do
|
823
|
+
|
824
|
+
let(:modified) do
|
825
|
+
# Buffer has 8 bytes but we can only write up to position 4
|
826
|
+
buffer.replace_int32(5, 42)
|
827
|
+
end
|
828
|
+
|
829
|
+
it 'raises ArgumentError' do
|
830
|
+
expect do
|
831
|
+
modified
|
832
|
+
end.to raise_error(ArgumentError, /Position.*is out of bounds/)
|
833
|
+
end
|
834
|
+
end
|
835
|
+
end
|
836
|
+
|
837
|
+
context 'when there is insufficient data in buffer' do
|
838
|
+
|
839
|
+
before do
|
840
|
+
buffer.put_bytes("aa")
|
841
|
+
end
|
842
|
+
|
843
|
+
let(:modified) do
|
844
|
+
buffer.replace_int32(1, 42)
|
845
|
+
end
|
846
|
+
|
847
|
+
it 'raises ArgumentError' do
|
848
|
+
expect do
|
849
|
+
modified
|
850
|
+
end.to raise_error(ArgumentError, /Buffer does not have enough data/)
|
851
|
+
end
|
852
|
+
end
|
853
|
+
end
|
854
|
+
end
|