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.
Files changed (116) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +2 -2
  3. data.tar.gz.sig +0 -0
  4. data/README.md +5 -1
  5. data/ext/bson/bson-native.h +14 -4
  6. data/ext/bson/init.c +25 -2
  7. data/ext/bson/read.c +61 -15
  8. data/ext/bson/util.c +40 -0
  9. data/ext/bson/write.c +17 -13
  10. data/lib/bson.rb +3 -0
  11. data/lib/bson/array.rb +21 -3
  12. data/lib/bson/binary.rb +41 -3
  13. data/lib/bson/boolean.rb +3 -1
  14. data/lib/bson/code.rb +15 -1
  15. data/lib/bson/code_with_scope.rb +17 -3
  16. data/lib/bson/db_pointer.rb +104 -0
  17. data/lib/bson/decimal128.rb +15 -1
  18. data/lib/bson/error.rb +17 -0
  19. data/lib/bson/ext_json.rb +374 -0
  20. data/lib/bson/float.rb +47 -1
  21. data/lib/bson/hash.rb +23 -3
  22. data/lib/bson/int32.rb +21 -1
  23. data/lib/bson/int64.rb +28 -3
  24. data/lib/bson/integer.rb +34 -0
  25. data/lib/bson/max_key.rb +12 -0
  26. data/lib/bson/min_key.rb +12 -0
  27. data/lib/bson/nil_class.rb +3 -1
  28. data/lib/bson/object.rb +27 -0
  29. data/lib/bson/object_id.rb +15 -1
  30. data/lib/bson/regexp.rb +19 -2
  31. data/lib/bson/specialized.rb +3 -1
  32. data/lib/bson/string.rb +3 -1
  33. data/lib/bson/symbol.rb +92 -3
  34. data/lib/bson/time.rb +28 -3
  35. data/lib/bson/timestamp.rb +15 -1
  36. data/lib/bson/undefined.rb +11 -0
  37. data/lib/bson/version.rb +1 -1
  38. data/spec/bson/binary_spec.rb +33 -3
  39. data/spec/bson/ext_json_parse_spec.rb +276 -0
  40. data/spec/bson/float_spec.rb +36 -0
  41. data/spec/bson/hash_spec.rb +70 -0
  42. data/spec/bson/int32_spec.rb +20 -0
  43. data/spec/bson/int64_spec.rb +38 -0
  44. data/spec/bson/integer_spec.rb +26 -0
  45. data/spec/bson/raw_spec.rb +22 -1
  46. data/spec/bson/symbol_raw_spec.rb +45 -0
  47. data/spec/bson/symbol_spec.rb +60 -0
  48. data/spec/{support → runners}/common_driver.rb +0 -0
  49. data/spec/runners/corpus.rb +182 -0
  50. data/spec/{support/corpus.rb → runners/corpus_legacy.rb} +40 -58
  51. data/spec/spec_helper.rb +9 -2
  52. data/spec/{bson/driver_bson_spec.rb → spec_tests/common_driver_spec.rb} +1 -0
  53. data/spec/{bson/corpus_spec.rb → spec_tests/corpus_legacy_spec.rb} +4 -4
  54. data/spec/spec_tests/corpus_spec.rb +124 -0
  55. data/spec/spec_tests/data/corpus/README.md +15 -0
  56. data/spec/spec_tests/data/corpus/array.json +49 -0
  57. data/spec/spec_tests/data/corpus/binary.json +85 -0
  58. data/spec/spec_tests/data/corpus/boolean.json +27 -0
  59. data/spec/spec_tests/data/corpus/code.json +67 -0
  60. data/spec/spec_tests/data/corpus/code_w_scope.json +78 -0
  61. data/spec/spec_tests/data/corpus/datetime.json +42 -0
  62. data/spec/spec_tests/data/corpus/dbpointer.json +56 -0
  63. data/spec/spec_tests/data/corpus/dbref.json +31 -0
  64. data/spec/spec_tests/data/corpus/decimal128-1.json +317 -0
  65. data/spec/spec_tests/data/corpus/decimal128-2.json +793 -0
  66. data/spec/spec_tests/data/corpus/decimal128-3.json +1771 -0
  67. data/spec/spec_tests/data/corpus/decimal128-4.json +117 -0
  68. data/spec/spec_tests/data/corpus/decimal128-5.json +402 -0
  69. data/spec/spec_tests/data/corpus/decimal128-6.json +119 -0
  70. data/spec/spec_tests/data/corpus/decimal128-7.json +323 -0
  71. data/spec/spec_tests/data/corpus/document.json +36 -0
  72. data/spec/spec_tests/data/corpus/double.json +87 -0
  73. data/spec/spec_tests/data/corpus/int32.json +43 -0
  74. data/spec/spec_tests/data/corpus/int64.json +43 -0
  75. data/spec/spec_tests/data/corpus/maxkey.json +12 -0
  76. data/spec/spec_tests/data/corpus/minkey.json +12 -0
  77. data/spec/spec_tests/data/corpus/multi-type-deprecated.json +15 -0
  78. data/spec/spec_tests/data/corpus/multi-type.json +11 -0
  79. data/spec/spec_tests/data/corpus/null.json +12 -0
  80. data/spec/spec_tests/data/corpus/oid.json +28 -0
  81. data/spec/spec_tests/data/corpus/regex.json +65 -0
  82. data/spec/spec_tests/data/corpus/string.json +72 -0
  83. data/spec/spec_tests/data/corpus/symbol.json +80 -0
  84. data/spec/spec_tests/data/corpus/timestamp.json +24 -0
  85. data/spec/spec_tests/data/corpus/top.json +240 -0
  86. data/spec/spec_tests/data/corpus/undefined.json +15 -0
  87. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/array.json +0 -0
  88. data/spec/{support/corpus-tests/failures → spec_tests/data/corpus_legacy}/binary.json +0 -0
  89. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/boolean.json +0 -0
  90. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/code.json +1 -1
  91. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/code_w_scope.json +1 -1
  92. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/document.json +1 -1
  93. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/double.json +1 -1
  94. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/failures/datetime.json +0 -0
  95. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/failures/dbpointer.json +0 -0
  96. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/failures/int64.json +0 -0
  97. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/failures/symbol.json +0 -0
  98. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/int32.json +1 -1
  99. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/maxkey.json +1 -1
  100. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/minkey.json +1 -1
  101. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/null.json +1 -1
  102. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/oid.json +0 -0
  103. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/regex.json +1 -1
  104. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/string.json +0 -0
  105. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/timestamp.json +1 -1
  106. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/top.json +0 -0
  107. data/spec/{support/corpus-tests/failures → spec_tests/data/corpus_legacy}/undefined.json +0 -0
  108. data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-1.json +0 -0
  109. data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-2.json +0 -0
  110. data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-3.json +0 -0
  111. data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-4.json +0 -0
  112. data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-5.json +0 -0
  113. data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-6.json +0 -0
  114. data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-7.json +0 -0
  115. metadata +170 -95
  116. metadata.gz.sig +2 -4
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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