bson 4.7.1 → 4.8.0
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 +4 -4
- checksums.yaml.gz.sig +2 -2
- data.tar.gz.sig +0 -0
- data/README.md +5 -1
- data/ext/bson/bson-native.h +14 -4
- data/ext/bson/init.c +25 -2
- data/ext/bson/read.c +61 -15
- data/ext/bson/util.c +40 -0
- data/ext/bson/write.c +17 -13
- data/lib/bson.rb +3 -0
- data/lib/bson/array.rb +21 -3
- data/lib/bson/binary.rb +41 -3
- data/lib/bson/boolean.rb +3 -1
- data/lib/bson/code.rb +15 -1
- data/lib/bson/code_with_scope.rb +17 -3
- data/lib/bson/db_pointer.rb +104 -0
- data/lib/bson/decimal128.rb +15 -1
- data/lib/bson/error.rb +17 -0
- data/lib/bson/ext_json.rb +374 -0
- data/lib/bson/float.rb +47 -1
- data/lib/bson/hash.rb +23 -3
- data/lib/bson/int32.rb +21 -1
- data/lib/bson/int64.rb +28 -3
- data/lib/bson/integer.rb +34 -0
- data/lib/bson/max_key.rb +12 -0
- data/lib/bson/min_key.rb +12 -0
- data/lib/bson/nil_class.rb +3 -1
- data/lib/bson/object.rb +27 -0
- data/lib/bson/object_id.rb +15 -1
- data/lib/bson/regexp.rb +19 -2
- data/lib/bson/specialized.rb +3 -1
- data/lib/bson/string.rb +3 -1
- data/lib/bson/symbol.rb +92 -3
- data/lib/bson/time.rb +28 -3
- data/lib/bson/timestamp.rb +15 -1
- data/lib/bson/undefined.rb +11 -0
- data/lib/bson/version.rb +1 -1
- data/spec/bson/binary_spec.rb +33 -3
- data/spec/bson/ext_json_parse_spec.rb +276 -0
- data/spec/bson/float_spec.rb +36 -0
- data/spec/bson/hash_spec.rb +70 -0
- data/spec/bson/int32_spec.rb +20 -0
- data/spec/bson/int64_spec.rb +38 -0
- data/spec/bson/integer_spec.rb +26 -0
- data/spec/bson/raw_spec.rb +22 -1
- data/spec/bson/symbol_raw_spec.rb +45 -0
- data/spec/bson/symbol_spec.rb +60 -0
- data/spec/{support → runners}/common_driver.rb +0 -0
- data/spec/runners/corpus.rb +182 -0
- data/spec/{support/corpus.rb → runners/corpus_legacy.rb} +40 -58
- data/spec/spec_helper.rb +9 -2
- 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} +4 -4
- 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 +85 -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 +24 -0
- data/spec/spec_tests/data/corpus/top.json +240 -0
- data/spec/spec_tests/data/corpus/undefined.json +15 -0
- data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/array.json +0 -0
- 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
- metadata +170 -95
- metadata.gz.sig +2 -4
data/spec/bson/float_spec.rb
CHANGED
@@ -26,4 +26,40 @@ describe Float do
|
|
26
26
|
it_behaves_like "a serializable bson element"
|
27
27
|
it_behaves_like "a deserializable bson element"
|
28
28
|
end
|
29
|
+
|
30
|
+
describe '#to_json' do
|
31
|
+
it 'returns float' do
|
32
|
+
42.0.to_json.should == '42.0'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#as_extended_json' do
|
37
|
+
context 'canonical mode' do
|
38
|
+
it 'returns $numberDouble' do
|
39
|
+
42.0.as_extended_json.should == {'$numberDouble' => '42.0'}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'relaxed mode' do
|
44
|
+
let(:serialized) do
|
45
|
+
42.0.as_extended_json(mode: :relaxed)
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'returns float' do
|
49
|
+
serialized.should be_a(Float)
|
50
|
+
serialized.should be_within(0.00001).of(42)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'legacy mode' do
|
55
|
+
let(:serialized) do
|
56
|
+
42.0.as_extended_json(mode: :legacy)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'returns float' do
|
60
|
+
serialized.should be_a(Float)
|
61
|
+
serialized.should be_within(0.00001).of(42)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
29
65
|
end
|
data/spec/bson/hash_spec.rb
CHANGED
@@ -157,6 +157,76 @@ describe Hash do
|
|
157
157
|
it_behaves_like "a serializable bson element"
|
158
158
|
it_behaves_like "a deserializable bson element"
|
159
159
|
end
|
160
|
+
|
161
|
+
context 'with symbol values' do
|
162
|
+
let(:value) { :foo }
|
163
|
+
|
164
|
+
let(:serialized) do
|
165
|
+
{foo: value}.to_bson.to_s
|
166
|
+
end
|
167
|
+
|
168
|
+
def perform_test(bson_type_to_use)
|
169
|
+
Symbol.class_eval do
|
170
|
+
alias_method :bson_type_orig, :bson_type
|
171
|
+
define_method(:bson_type) do
|
172
|
+
bson_type_to_use
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
begin
|
177
|
+
yield
|
178
|
+
ensure
|
179
|
+
Symbol.class_eval do
|
180
|
+
alias_method :bson_type, :bson_type_orig
|
181
|
+
remove_method :bson_type_orig
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
let(:bson_with_symbol) do
|
187
|
+
"\x12\x00\x00\x00\x0Efoo\x00\x04\x00\x00\x00bar\x00\x00".force_encoding('binary')
|
188
|
+
end
|
189
|
+
|
190
|
+
let(:deserialized) do
|
191
|
+
Hash.from_bson(BSON::ByteBuffer.new(bson_with_symbol))
|
192
|
+
end
|
193
|
+
|
194
|
+
context 'when Symbol#bson_type is set to symbol' do
|
195
|
+
let(:bson_type_to_use) { BSON::Symbol::BSON_TYPE }
|
196
|
+
|
197
|
+
let(:expected) do
|
198
|
+
"\x12\x00\x00\x00\x0Efoo\x00\x04\x00\x00\x00foo\x00\x00".force_encoding('binary')
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'serializes to BSON symbol' do
|
202
|
+
perform_test(bson_type_to_use) do
|
203
|
+
serialized
|
204
|
+
end.should == expected
|
205
|
+
end
|
206
|
+
|
207
|
+
it 'deserializes to Symbol' do
|
208
|
+
deserialized.should == {'foo' => :bar}
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
context 'when Symbol#bson_type is set to string' do
|
213
|
+
let(:bson_type_to_use) { BSON::String::BSON_TYPE }
|
214
|
+
|
215
|
+
let(:expected) do
|
216
|
+
"\x12\x00\x00\x00\x02foo\x00\x04\x00\x00\x00foo\x00\x00".force_encoding('binary')
|
217
|
+
end
|
218
|
+
|
219
|
+
it 'serializes to BSON string' do
|
220
|
+
perform_test(bson_type_to_use) do
|
221
|
+
serialized
|
222
|
+
end.should == expected
|
223
|
+
end
|
224
|
+
|
225
|
+
it 'deserializes to Symbol' do
|
226
|
+
deserialized.should == {'foo' => :bar}
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
160
230
|
end
|
161
231
|
|
162
232
|
describe '#to_bson' do
|
data/spec/bson/int32_spec.rb
CHANGED
@@ -253,4 +253,24 @@ describe BSON::Int32 do
|
|
253
253
|
expect(obj.value).to eq(12345)
|
254
254
|
end
|
255
255
|
end
|
256
|
+
|
257
|
+
describe '#as_extended_json' do
|
258
|
+
context 'canonical mode' do
|
259
|
+
it 'returns $numberInt' do
|
260
|
+
described_class.new(42).as_extended_json.should == {'$numberInt' => '42'}
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
context 'relaxed mode' do
|
265
|
+
it 'returns integer' do
|
266
|
+
described_class.new(42).as_extended_json(mode: :relaxed).should == 42
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
context 'legacy mode' do
|
271
|
+
it 'returns integer' do
|
272
|
+
described_class.new(42).as_extended_json(mode: :legacy).should be 42
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
256
276
|
end
|
data/spec/bson/int64_spec.rb
CHANGED
@@ -71,6 +71,25 @@ describe BSON::Int64 do
|
|
71
71
|
it_behaves_like "a bson element"
|
72
72
|
it_behaves_like "a deserializable bson element"
|
73
73
|
|
74
|
+
context 'canonical deserialization' do
|
75
|
+
let(:integer) { 42 }
|
76
|
+
|
77
|
+
let(:bson) do
|
78
|
+
BSON::ByteBuffer.new(BSON::Int64.new(integer).to_bson.to_s)
|
79
|
+
end
|
80
|
+
|
81
|
+
let(:deserialized) do
|
82
|
+
described_class.from_bson(bson, mode: :bson)
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'deserializes to BSON::Int64' do
|
86
|
+
deserialized.class.should be BSON::Int64
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'has the correct value' do
|
90
|
+
deserialized.value.should == 42
|
91
|
+
end
|
92
|
+
end
|
74
93
|
|
75
94
|
context "when the integer is within the MRI Fixnum range" do
|
76
95
|
|
@@ -299,4 +318,23 @@ describe BSON::Int64 do
|
|
299
318
|
end
|
300
319
|
end
|
301
320
|
|
321
|
+
describe '#as_extended_json' do
|
322
|
+
context 'canonical mode' do
|
323
|
+
it 'returns $numberLong' do
|
324
|
+
described_class.new(42).as_extended_json.should == {'$numberLong' => '42'}
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
context 'relaxed mode' do
|
329
|
+
it 'returns integer' do
|
330
|
+
described_class.new(42).as_extended_json(mode: :relaxed).should == 42
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
context 'legacy mode' do
|
335
|
+
it 'returns integer' do
|
336
|
+
described_class.new(42).as_extended_json(mode: :legacy).should be 42
|
337
|
+
end
|
338
|
+
end
|
339
|
+
end
|
302
340
|
end
|
data/spec/bson/integer_spec.rb
CHANGED
@@ -68,4 +68,30 @@ describe Integer do
|
|
68
68
|
expect(obj.to_bson_key).to eq(encoded)
|
69
69
|
end
|
70
70
|
end
|
71
|
+
|
72
|
+
describe '#to_json' do
|
73
|
+
it 'returns integer' do
|
74
|
+
42.to_json.should == '42'
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe '#as_extended_json' do
|
79
|
+
context 'canonical mode' do
|
80
|
+
it 'returns $numberInt' do
|
81
|
+
42.as_extended_json.should == {'$numberInt' => '42'}
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context 'relaxed mode' do
|
86
|
+
it 'returns integer' do
|
87
|
+
42.as_extended_json(mode: :relaxed).should be 42
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context 'legacy mode' do
|
92
|
+
it 'returns integer' do
|
93
|
+
42.as_extended_json(mode: :legacy).should be 42
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
71
97
|
end
|
data/spec/bson/raw_spec.rb
CHANGED
@@ -12,13 +12,34 @@ describe Regexp::Raw do
|
|
12
12
|
described_class.new(pattern, 'im')
|
13
13
|
end
|
14
14
|
|
15
|
-
it "returns the regex pattern and options" do
|
15
|
+
it "returns the legacy serialization including regex pattern and options" do
|
16
16
|
expect(object.as_json).to eq({ "$regex" => "\\W+", "$options" => "im" })
|
17
17
|
end
|
18
18
|
|
19
19
|
it_behaves_like "a JSON serializable object"
|
20
20
|
end
|
21
21
|
|
22
|
+
describe '#as_extended_json' do
|
23
|
+
|
24
|
+
let(:object) do
|
25
|
+
described_class.new(pattern, 'im')
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'legacy mode' do
|
29
|
+
it "returns the legacy serialization including regex pattern and options" do
|
30
|
+
expect(object.as_extended_json(mode: :legacy)).to eq({ "$regex" => "\\W+", "$options" => "im" })
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'canonical/relaxed mode' do
|
35
|
+
it "returns the extended json 2.0 serialization" do
|
36
|
+
expect(object.as_extended_json).to eq(
|
37
|
+
"$regularExpression" => {'pattern' => "\\W+", "options" => "im"}
|
38
|
+
)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
22
43
|
describe "#to_bson/#from_bson" do
|
23
44
|
|
24
45
|
let(:options) { 'ilmsux' }
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# Copyright (C) 2020 MongoDB Inc.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require "spec_helper"
|
16
|
+
|
17
|
+
describe BSON::Symbol::Raw do
|
18
|
+
describe '#==' do
|
19
|
+
let(:one) { described_class.new('foo') }
|
20
|
+
let(:two) { described_class.new('foo') }
|
21
|
+
let(:three) { described_class.new('bar') }
|
22
|
+
|
23
|
+
it 'compares equal' do
|
24
|
+
one.should == two
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'compares not equal' do
|
28
|
+
one.should_not == three
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#eql?' do
|
33
|
+
let(:one) { described_class.new('foo') }
|
34
|
+
let(:two) { described_class.new('foo') }
|
35
|
+
let(:three) { described_class.new('bar') }
|
36
|
+
|
37
|
+
it 'compares equal' do
|
38
|
+
one.should be_eql(two)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'compares not equal' do
|
42
|
+
one.should_not be_eql(three)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/spec/bson/symbol_spec.rb
CHANGED
@@ -32,6 +32,66 @@ describe Symbol do
|
|
32
32
|
it_behaves_like "a bson element"
|
33
33
|
it_behaves_like "a serializable bson element"
|
34
34
|
it_behaves_like "a deserializable bson element"
|
35
|
+
|
36
|
+
context 'canonical deserialization' do
|
37
|
+
let(:bson) do
|
38
|
+
BSON::ByteBuffer.new(BSON::Symbol::Raw.new(obj).to_bson.to_s)
|
39
|
+
end
|
40
|
+
|
41
|
+
let(:deserialized) do
|
42
|
+
described_class.from_bson(bson, mode: :bson)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'deserializes to BSON::Symbol::Raw' do
|
46
|
+
deserialized.class.should be BSON::Symbol::Raw
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'has the correct value' do
|
50
|
+
deserialized.to_sym.should be obj
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'when changing bson_type' do
|
55
|
+
def perform_test(bson_type_to_use)
|
56
|
+
Symbol.class_eval do
|
57
|
+
alias_method :bson_type_orig, :bson_type
|
58
|
+
define_method(:bson_type) do
|
59
|
+
bson_type_to_use
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
begin
|
64
|
+
yield
|
65
|
+
ensure
|
66
|
+
Symbol.class_eval do
|
67
|
+
alias_method :bson_type, :bson_type_orig
|
68
|
+
remove_method :bson_type_orig
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
let(:value) { :foo }
|
74
|
+
|
75
|
+
let(:serialized) do
|
76
|
+
value.to_bson.to_s
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'when bson_type is set to symbol' do
|
80
|
+
it 'serializes to BSON string' do
|
81
|
+
perform_test(BSON::Symbol::BSON_TYPE) do
|
82
|
+
serialized
|
83
|
+
end.should == "\x04\x00\x00\x00foo\x00".force_encoding('binary')
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context 'when bson_type is set to string' do
|
88
|
+
it 'serializes to BSON string' do
|
89
|
+
perform_test(BSON::String::BSON_TYPE) do
|
90
|
+
serialized
|
91
|
+
end.should == "\x04\x00\x00\x00foo\x00".force_encoding('binary')
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
35
95
|
end
|
36
96
|
|
37
97
|
describe "#to_bson_key" do
|
File without changes
|
@@ -0,0 +1,182 @@
|
|
1
|
+
# Copyright (C) 2016-2019 MongoDB, Inc.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'json'
|
16
|
+
require 'forwardable'
|
17
|
+
|
18
|
+
module BSON
|
19
|
+
module Corpus
|
20
|
+
|
21
|
+
# Represents a test from the driver BSON Corpus.
|
22
|
+
#
|
23
|
+
# @since 4.2.0
|
24
|
+
class Spec
|
25
|
+
|
26
|
+
# The spec description.
|
27
|
+
#
|
28
|
+
# @return [ String ] The spec description.
|
29
|
+
#
|
30
|
+
# @since 4.2.0
|
31
|
+
attr_reader :description
|
32
|
+
|
33
|
+
# The document key of the object to test.
|
34
|
+
#
|
35
|
+
# @return [ String ] The document key.
|
36
|
+
#
|
37
|
+
# @since 4.2.0
|
38
|
+
attr_reader :test_key
|
39
|
+
|
40
|
+
# Instantiate the new spec.
|
41
|
+
#
|
42
|
+
# @example Create the spec.
|
43
|
+
# Spec.new(file)
|
44
|
+
#
|
45
|
+
# @param [ String ] file The name of the json file.
|
46
|
+
#
|
47
|
+
# @since 4.2.0
|
48
|
+
def initialize(file)
|
49
|
+
@spec = ::JSON.parse(File.read(file).force_encoding('utf-8'))
|
50
|
+
end
|
51
|
+
|
52
|
+
def description
|
53
|
+
@spec['description']
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_key
|
57
|
+
@spec['test_key']
|
58
|
+
end
|
59
|
+
|
60
|
+
def valid_tests
|
61
|
+
@valid_tests ||=
|
62
|
+
@spec['valid']&.map do |test_spec|
|
63
|
+
ValidTest.new(self, test_spec)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def decode_error_tests
|
68
|
+
@decode_error_tests ||=
|
69
|
+
@spec['decodeErrors']&.map do |test_spec|
|
70
|
+
DecodeErrorTest.new(self, test_spec)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def parse_error_tests
|
75
|
+
@parse_error_tests ||=
|
76
|
+
@spec['parseErrors']&.map do |test_spec|
|
77
|
+
ParseErrorTest.new(self, test_spec)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# The class of the bson object to test.
|
82
|
+
#
|
83
|
+
# @example Get the class of the object to test.
|
84
|
+
# spec.klass
|
85
|
+
#
|
86
|
+
# @return [ Class ] The object class.
|
87
|
+
#
|
88
|
+
# @since 4.2.0
|
89
|
+
def klass
|
90
|
+
@klass ||= BSON.const_get(description)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# Represents a single BSON Corpus test.
|
95
|
+
#
|
96
|
+
# @since 4.2.0
|
97
|
+
class ValidTest
|
98
|
+
extend Forwardable
|
99
|
+
|
100
|
+
# Instantiate the new Test.
|
101
|
+
#
|
102
|
+
# @example Create the test.
|
103
|
+
# Test.new(test)
|
104
|
+
#
|
105
|
+
# @param [ Corpus::Spec ] spec The test specification.
|
106
|
+
# @param [ Hash ] test The test specification.
|
107
|
+
#
|
108
|
+
# @since 4.2.0
|
109
|
+
def initialize(spec, test_params)
|
110
|
+
@spec = spec
|
111
|
+
test_params = test_params.dup
|
112
|
+
%w(
|
113
|
+
description canonical_extjson relaxed_extjson
|
114
|
+
degenerate_extjson converted_extjson
|
115
|
+
lossy
|
116
|
+
).each do |key|
|
117
|
+
instance_variable_set("@#{key}", test_params.delete(key))
|
118
|
+
end
|
119
|
+
%w(
|
120
|
+
canonical_bson degenerate_bson converted_bson
|
121
|
+
lossy
|
122
|
+
).each do |key|
|
123
|
+
if test_params.key?(key)
|
124
|
+
instance_variable_set("@#{key}", decode_hex(test_params.delete(key)))
|
125
|
+
end
|
126
|
+
end
|
127
|
+
unless test_params.empty?
|
128
|
+
raise "Test params has unprocessed keys: #{test_params}"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def_delegators :@spec, :test_key
|
133
|
+
|
134
|
+
attr_reader :description,
|
135
|
+
:canonical_bson,
|
136
|
+
:degenerate_bson,
|
137
|
+
:converted_bson,
|
138
|
+
:canonical_extjson,
|
139
|
+
:relaxed_extjson,
|
140
|
+
:degenerate_extjson,
|
141
|
+
:converted_extjson
|
142
|
+
|
143
|
+
def lossy?
|
144
|
+
!!@lossy
|
145
|
+
end
|
146
|
+
|
147
|
+
def canonical_extjson_doc
|
148
|
+
::JSON.parse(canonical_extjson)
|
149
|
+
end
|
150
|
+
|
151
|
+
def relaxed_extjson_doc
|
152
|
+
relaxed_extjson && ::JSON.parse(relaxed_extjson)
|
153
|
+
end
|
154
|
+
|
155
|
+
private
|
156
|
+
|
157
|
+
def decode_hex(obj)
|
158
|
+
[ obj ].pack('H*')
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
class DecodeErrorTest
|
163
|
+
def initialize(spec, test_params)
|
164
|
+
@spec = spec
|
165
|
+
@description = test_params['description']
|
166
|
+
@bson = test_params['bson']
|
167
|
+
end
|
168
|
+
|
169
|
+
attr_reader :description, :bson
|
170
|
+
end
|
171
|
+
|
172
|
+
class ParseErrorTest
|
173
|
+
def initialize(spec, test_params)
|
174
|
+
@spec = spec
|
175
|
+
@description = test_params['description']
|
176
|
+
@string = test_params['string']
|
177
|
+
end
|
178
|
+
|
179
|
+
attr_reader :description, :string
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|