bson 4.1.1 → 4.2.0.rc0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/Rakefile +18 -3
  5. data/ext/bson/{native.c → bson_native.c} +48 -8
  6. data/ext/bson/extconf.rb +1 -1
  7. data/ext/bson/native-endian.h +1 -1
  8. data/lib/bson.rb +3 -1
  9. data/lib/bson/config.rb +1 -1
  10. data/lib/bson/decimal128.rb +318 -0
  11. data/lib/bson/decimal128/builder.rb +448 -0
  12. data/lib/bson/document.rb +2 -2
  13. data/lib/bson/environment.rb +13 -1
  14. data/lib/bson/int32.rb +46 -0
  15. data/lib/bson/int64.rb +46 -0
  16. data/lib/bson/max_key.rb +1 -1
  17. data/lib/bson/min_key.rb +1 -1
  18. data/lib/bson/object_id.rb +2 -1
  19. data/lib/bson/open_struct.rb +57 -0
  20. data/lib/bson/regexp.rb +1 -1
  21. data/lib/bson/registry.rb +1 -1
  22. data/lib/bson/version.rb +2 -2
  23. data/spec/bson/decimal128_spec.rb +1583 -0
  24. data/spec/bson/document_spec.rb +1 -1
  25. data/spec/bson/driver_bson_spec.rb +77 -0
  26. data/spec/bson/int32_spec.rb +58 -0
  27. data/spec/bson/int64_spec.rb +58 -0
  28. data/spec/bson/open_struct_spec.rb +144 -0
  29. data/spec/spec_helper.rb +4 -0
  30. data/spec/support/common_driver.rb +347 -0
  31. data/spec/support/driver-spec-tests/decimal128/decimal128-1.json +363 -0
  32. data/spec/support/driver-spec-tests/decimal128/decimal128-2.json +793 -0
  33. data/spec/support/driver-spec-tests/decimal128/decimal128-3.json +1771 -0
  34. data/spec/support/driver-spec-tests/decimal128/decimal128-4.json +165 -0
  35. data/spec/support/driver-spec-tests/decimal128/decimal128-5.json +402 -0
  36. data/spec/support/driver-spec-tests/decimal128/decimal128-6.json +131 -0
  37. data/spec/support/driver-spec-tests/decimal128/decimal128-7.json +327 -0
  38. metadata +29 -4
  39. metadata.gz.sig +0 -0
@@ -887,7 +887,7 @@ describe BSON::Document do
887
887
  end
888
888
  end
889
889
 
890
- context "when binary strings with utf-8 values exist", if: BSON::Environment.jruby? && (JRUBY_VERSION !~ /9.0/) do
890
+ context "when binary strings with utf-8 values exist", if: BSON::Environment.jruby? && (JRUBY_VERSION < '9') do
891
891
 
892
892
  let(:string) { "europäisch" }
893
893
  let(:document) do
@@ -0,0 +1,77 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Driver common bson tests' do
4
+
5
+ specs = DRIVER_COMMON_BSON_TESTS.map { |file| BSON::CommonDriver::Spec.new(file) }
6
+
7
+ specs.each do |spec|
8
+
9
+ context(spec.description) do
10
+
11
+ spec.valid_tests.each do |test|
12
+
13
+ context(test.description << ' - ' << test.string) do
14
+
15
+ it 'decodes the subject and displays as the correct string' do
16
+ expect(test.object.to_s).to eq(test.expected_to_string)
17
+ end
18
+
19
+ it 'encodes the decoded object correctly (roundtrips)' do
20
+ expect(test.reencoded_hex).to eq(test.subject.upcase)
21
+ end
22
+
23
+ it 'creates the correct object from extended json', if: test.from_ext_json? do
24
+ expect(test.from_json_string).to eq(test.object)
25
+ end
26
+
27
+ it 'creates the correct extended json document from the decoded object', if: test.to_ext_json? do
28
+ expect(test.document_as_json).to eq(test.ext_json)
29
+ end
30
+
31
+ it 'parses the string value to the same value as the decoded document', if: test.from_string? do
32
+ expect(BSON::Decimal128.new(test.string)).to eq(test.object)
33
+ end
34
+
35
+ it 'parses the #to_s (match_string) value to the same value as the decoded document', if: test.match_string do
36
+ expect(BSON::Decimal128.new(test.match_string)).to eq(test.object)
37
+ end
38
+
39
+ it 'creates the correct object from a non canonical string and then prints to the correct string', if: test.match_string do
40
+ expect(BSON::Decimal128.new(test.string).to_s).to eq(test.match_string)
41
+ end
42
+
43
+ it 'can be converted to a native type' do
44
+ expect(test.native_type_conversion).to be_a(test.native_type)
45
+ end
46
+ end
47
+ end
48
+
49
+ spec.invalid_tests.each do |test|
50
+
51
+ context(test.description << " - " << test.subject ) do
52
+
53
+ let(:error) do
54
+ ex = nil
55
+ begin
56
+ test.parse_invalid_string
57
+ rescue => e
58
+ ex = e
59
+ end
60
+ ex
61
+ end
62
+
63
+ let(:valid_errors) do
64
+ [
65
+ BSON::Decimal128::InvalidString,
66
+ BSON::Decimal128::InvalidRange
67
+ ]
68
+ end
69
+
70
+ it 'raises an exception when parsing' do
71
+ expect(error.class).to satisfy { |e| valid_errors.include?(e) }
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -16,6 +16,42 @@ require "spec_helper"
16
16
 
17
17
  describe BSON::Int32 do
18
18
 
19
+ describe "#intiialize" do
20
+
21
+ let(:obj) { described_class.new(integer) }
22
+
23
+ context "when the integer is 32-bit" do
24
+
25
+ let(:integer) { Integer::MAX_32BIT }
26
+
27
+ it "wraps the integer" do
28
+ expect(obj.instance_variable_get(:@integer)).to be(integer)
29
+ end
30
+ end
31
+
32
+ context "when the integer is too large" do
33
+
34
+ let(:integer) { Integer::MAX_32BIT + 1 }
35
+
36
+ it "raises an out of range error" do
37
+ expect {
38
+ obj
39
+ }.to raise_error(RangeError)
40
+ end
41
+ end
42
+
43
+ context "when the integer is too small" do
44
+
45
+ let(:integer) { Integer::MIN_32BIT - 1 }
46
+
47
+ it "raises an out of range error" do
48
+ expect {
49
+ obj
50
+ }.to raise_error(RangeError)
51
+ end
52
+ end
53
+ end
54
+
19
55
  describe "#from_bson" do
20
56
 
21
57
  let(:type) { 16.chr }
@@ -41,4 +77,26 @@ describe BSON::Int32 do
41
77
  expect(BSON::Int32.from_bson(encoded_2)).to eq(decoded_2)
42
78
  end
43
79
  end
80
+
81
+ describe "#to_bson" do
82
+
83
+ context "when the integer is 32 bit" do
84
+
85
+ let(:type) { 16.chr }
86
+ let(:obj) { BSON::Int32.new(Integer::MAX_32BIT - 1) }
87
+ let(:bson) { [ Integer::MAX_32BIT - 1 ].pack(BSON::Int32::PACK) }
88
+
89
+ it_behaves_like "a serializable bson element"
90
+ end
91
+ end
92
+
93
+ describe "#to_bson_key" do
94
+
95
+ let(:obj) { BSON::Int32.new(Integer::MAX_32BIT - 1) }
96
+ let(:encoded) { (Integer::MAX_32BIT - 1).to_s }
97
+
98
+ it "returns the key as a string" do
99
+ expect(obj.to_bson_key).to eq(encoded)
100
+ end
101
+ end
44
102
  end
@@ -16,6 +16,42 @@ require "spec_helper"
16
16
 
17
17
  describe BSON::Int64 do
18
18
 
19
+ describe "#intiialize" do
20
+
21
+ let(:obj) { described_class.new(integer) }
22
+
23
+ context "when the integer is 64-bit" do
24
+
25
+ let(:integer) { Integer::MAX_64BIT - 1 }
26
+
27
+ it "wraps the integer" do
28
+ expect(obj.instance_variable_get(:@integer)).to be(integer)
29
+ end
30
+ end
31
+
32
+ context "when the integer is too large" do
33
+
34
+ let(:integer) { Integer::MAX_64BIT + 1 }
35
+
36
+ it "raises an out of range error" do
37
+ expect {
38
+ obj
39
+ }.to raise_error(RangeError)
40
+ end
41
+ end
42
+
43
+ context "when the integer is too small" do
44
+
45
+ let(:integer) { Integer::MIN_64BIT - 1 }
46
+
47
+ it "raises an out of range error" do
48
+ expect {
49
+ obj
50
+ }.to raise_error(RangeError)
51
+ end
52
+ end
53
+ end
54
+
19
55
  describe "#from_bson" do
20
56
 
21
57
  let(:type) { 18.chr }
@@ -25,4 +61,26 @@ describe BSON::Int64 do
25
61
  it_behaves_like "a bson element"
26
62
  it_behaves_like "a deserializable bson element"
27
63
  end
64
+
65
+ describe "#to_bson" do
66
+
67
+ context "when the integer is 64 bit" do
68
+
69
+ let(:type) { 18.chr }
70
+ let(:obj) { BSON::Int64.new(Integer::MAX_64BIT - 1) }
71
+ let(:bson) { [ Integer::MAX_64BIT - 1 ].pack(BSON::Int64::PACK) }
72
+
73
+ it_behaves_like "a serializable bson element"
74
+ end
75
+ end
76
+
77
+ describe "#to_bson_key" do
78
+
79
+ let(:obj) { BSON::Int64.new(Integer::MAX_64BIT - 1) }
80
+ let(:encoded) { (Integer::MAX_64BIT - 1).to_s }
81
+
82
+ it "returns the key as a string" do
83
+ expect(obj.to_bson_key).to eq(encoded)
84
+ end
85
+ end
28
86
  end
@@ -0,0 +1,144 @@
1
+ # Copyright (C) 2016 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 OpenStruct do
18
+
19
+ describe "#to_bson" do
20
+
21
+ let(:type) { 3.chr }
22
+
23
+ it_behaves_like "a bson element"
24
+
25
+ context "when the struct is a single level" do
26
+
27
+ let(:obj) do
28
+ described_class.new({"key" => "value" })
29
+ end
30
+
31
+ let(:bson) do
32
+ "#{20.to_bson.to_s}#{String::BSON_TYPE}key#{BSON::NULL_BYTE}" +
33
+ "#{6.to_bson.to_s}value#{BSON::NULL_BYTE}#{BSON::NULL_BYTE}"
34
+ end
35
+
36
+ it_behaves_like "a serializable bson element"
37
+ end
38
+
39
+ context "when the struct has invalid keys" do
40
+
41
+ let(:obj) do
42
+ described_class.new({ "$testing" => "value" })
43
+ end
44
+
45
+ context "when validating keys" do
46
+
47
+ context "when validating globally" do
48
+
49
+ before do
50
+ BSON::Config.validating_keys = true
51
+ end
52
+
53
+ after do
54
+ BSON::Config.validating_keys = false
55
+ end
56
+
57
+ it "raises an error" do
58
+ expect {
59
+ obj.to_bson
60
+ }.to raise_error(BSON::String::IllegalKey)
61
+ end
62
+
63
+ context "when the struct contains an array of documents containing invalid keys" do
64
+
65
+ let(:obj) do
66
+ described_class.new({ "array" => [{ "$testing" => "value" }] })
67
+ end
68
+
69
+ it "raises an error" do
70
+ expect {
71
+ obj.to_bson
72
+ }.to raise_error(BSON::String::IllegalKey)
73
+ end
74
+ end
75
+ end
76
+
77
+ context "when validating locally" do
78
+
79
+ it "raises an error" do
80
+ expect {
81
+ obj.to_bson(BSON::ByteBuffer.new, true)
82
+ }.to raise_error(BSON::String::IllegalKey)
83
+ end
84
+
85
+ context "when the struct contains an array of documents containing invalid keys" do
86
+
87
+ let(:obj) do
88
+ described_class.new({ "array" => [{ "$testing" => "value" }] })
89
+ end
90
+
91
+ it "raises an error" do
92
+ expect {
93
+ obj.to_bson(BSON::ByteBuffer.new, true)
94
+ }.to raise_error(BSON::String::IllegalKey)
95
+ end
96
+ end
97
+ end
98
+ end
99
+
100
+ context "when not validating keys" do
101
+
102
+ let(:bson) do
103
+ "#{25.to_bson.to_s}#{String::BSON_TYPE}$testing#{BSON::NULL_BYTE}" +
104
+ "#{6.to_bson.to_s}value#{BSON::NULL_BYTE}#{BSON::NULL_BYTE}"
105
+ end
106
+
107
+ it "serializes the struct" do
108
+ expect(obj.to_bson.to_s).to eq(bson)
109
+ end
110
+
111
+ context "when the struct contains an array of documents containing invalid keys" do
112
+
113
+ let(:obj) do
114
+ described_class.new({ "array" => [{ "$testing" => "value" }] })
115
+ end
116
+
117
+ let(:bson) do
118
+ "#{45.to_bson.to_s}#{Array::BSON_TYPE}array#{BSON::NULL_BYTE}" +
119
+ "#{[{ "$testing" => "value" }].to_bson.to_s}#{BSON::NULL_BYTE}"
120
+ end
121
+
122
+ it "serializes the struct" do
123
+ expect(obj.to_bson.to_s).to eq(bson)
124
+ end
125
+ end
126
+ end
127
+ end
128
+
129
+ context "when the struct is embedded" do
130
+
131
+ let(:obj) do
132
+ described_class.new({ "field" => OpenStruct.new({ "key" => "value" })})
133
+ end
134
+
135
+ let(:bson) do
136
+ "#{32.to_bson.to_s}#{Hash::BSON_TYPE}field#{BSON::NULL_BYTE}" +
137
+ "#{20.to_bson.to_s}#{String::BSON_TYPE}key#{BSON::NULL_BYTE}" +
138
+ "#{6.to_bson.to_s}value#{BSON::NULL_BYTE}#{BSON::NULL_BYTE}#{BSON::NULL_BYTE}"
139
+ end
140
+
141
+ it_behaves_like "a serializable bson element"
142
+ end
143
+ end
144
+ end
@@ -12,9 +12,13 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ CURRENT_PATH = File.expand_path(File.dirname(__FILE__))
16
+ DRIVER_COMMON_BSON_TESTS = Dir.glob("#{CURRENT_PATH}/support/driver-spec-tests/**/*.json")
17
+
15
18
  $LOAD_PATH.unshift(File.dirname(__FILE__))
16
19
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
17
20
 
21
+ require "ostruct"
18
22
  require "bson"
19
23
  require "json"
20
24
  require "rspec"
@@ -0,0 +1,347 @@
1
+ # Copyright (C) 2016 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 'bigdecimal'
17
+
18
+ module BSON
19
+ module CommonDriver
20
+
21
+ # Represents a Common Driver specification test.
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 yaml file.
46
+ #
47
+ # @since 4.2.0
48
+ def initialize(file)
49
+ @spec = ::JSON.parse(File.read(file))
50
+ @valid = @spec['valid'] || []
51
+ @invalid = @spec['parseErrors'] || []
52
+ @description = @spec['description']
53
+ @test_key = @spec['test_key']
54
+ end
55
+
56
+ # Get a list of tests that don't raise exceptions.
57
+ #
58
+ # @example Get the list of valid tests.
59
+ # spec.valid_tests
60
+ #
61
+ # @return [ Array<BSON::CommonDriver::Test> ] The list of valid Tests.
62
+ #
63
+ # @since 4.2.0
64
+ def valid_tests
65
+ @valid_tests ||=
66
+ @valid.collect do |test|
67
+ BSON::CommonDriver::Test.new(self, test)
68
+ end
69
+ end
70
+
71
+ # Get a list of tests that raise exceptions.
72
+ #
73
+ # @example Get the list of invalid tests.
74
+ # spec.invalid_tests
75
+ #
76
+ # @return [ Array<BSON::CommonDriver::Test> ] The list of invalid Tests.
77
+ #
78
+ # @since 4.2.0
79
+ def invalid_tests
80
+ @invalid_tests ||=
81
+ @invalid.collect do |test|
82
+ BSON::CommonDriver::Test.new(self, test)
83
+ end
84
+ end
85
+
86
+ # The class of the bson object to test.
87
+ #
88
+ # @example Get the class of the object to test.
89
+ # spec.klass
90
+ #
91
+ # @return [ Class ] The object class.
92
+ #
93
+ # @since 4.2.0
94
+ def klass
95
+ @klass ||= BSON.const_get(description)
96
+ end
97
+ end
98
+
99
+ # Represents a single CommonDriver test.
100
+ #
101
+ # @since 4.2.0
102
+ class Test
103
+
104
+ # The test description.
105
+ #
106
+ # @return [ String ] The test description.
107
+ #
108
+ # @since 4.2.0
109
+ attr_reader :description
110
+
111
+ # The test subject.
112
+ #
113
+ # @return [ String ] The test subject.
114
+ #
115
+ # @since 4.2.0
116
+ attr_reader :subject
117
+
118
+ # The string to use to create a Decimal128.
119
+ #
120
+ # @return [ String ] The string to use in creating a Decimal128 object.
121
+ #
122
+ # @since 4.2.0
123
+ attr_reader :string
124
+
125
+ # The expected string representation of the Decimal128 object.
126
+ #
127
+ # @return [ String ] The object as a string.
128
+ #
129
+ # @since 4.2.0
130
+ attr_reader :match_string
131
+
132
+ # The json representation of the object.
133
+ #
134
+ # @return [ Hash ] The json representation of the object.
135
+ #
136
+ # @since 4.2.0
137
+ attr_reader :ext_json
138
+
139
+ # Instantiate the new Test.
140
+ #
141
+ # @example Create the test.
142
+ # Test.new(test)
143
+ #
144
+ # @param [ CommonDriver::Spec ] spec The test specification.
145
+ # @param [ Hash ] test The test specification.
146
+ #
147
+ # @since 4.2.0
148
+ def initialize(spec, test)
149
+ @spec = spec
150
+ @description = test['description']
151
+ @string = test['string']
152
+ @match_string = test['match_string']
153
+ @ext_json = ::JSON.parse(test['extjson']) if test['extjson']
154
+ @from_ext_json = test['from_extjson'].nil? ? true : test['from_extjson']
155
+ @to_ext_json = test['to_extjson'].nil? ? true : test['to_extjson']
156
+ @subject = test['subject']
157
+ @test_key = spec.test_key
158
+ end
159
+
160
+ # Get the reencoded document in hex format.
161
+ #
162
+ # @example Get the reencoded document as hex.
163
+ # test.reencoded_hex
164
+ #
165
+ # @return [ String ] The reencoded document in hex format.
166
+ #
167
+ # @since 4.2.0
168
+ def reencoded_hex
169
+ decoded_document.to_bson.to_s.unpack("H*").first.upcase
170
+ end
171
+
172
+ # The object tested.
173
+ #
174
+ # @example Get the object for this test.
175
+ # test.object
176
+ #
177
+ # @return [ BSON::Object ] The object.
178
+ #
179
+ # @since 4.2.0
180
+ def object
181
+ @object ||= decoded_document[@test_key]
182
+ end
183
+
184
+ # The object as json, in a document with the test key.
185
+ #
186
+ # @example Get a document with the object at the test key.
187
+ # test.document_as_json
188
+ #
189
+ # @return [ BSON::Document ] The json document.
190
+ #
191
+ # @since 4.2.0
192
+ def document_as_json
193
+ { @test_key => object.as_json }
194
+ end
195
+
196
+ # Use the string in the extended json to instantiate the bson object.
197
+ #
198
+ # @example Get a bson object from the string in the extended json.
199
+ # test.from_json
200
+ #
201
+ # @return [ BSON::Object ] The BSON object.
202
+ #
203
+ # @since 4.2.0
204
+ def from_json_string
205
+ klass.from_string(@ext_json[@test_key][klass::EXTENDED_JSON_KEY])
206
+ end
207
+
208
+ # Create an object from the given test string.
209
+ #
210
+ # @example
211
+ # test.parse_string
212
+ #
213
+ # @return [ BSON::Object ] The object.
214
+ #
215
+ # @since 4.2.0
216
+ def parse_string
217
+ klass.from_string(string)
218
+ end
219
+
220
+ # Attempt to create an object from an invalid string.
221
+ #
222
+ # @example
223
+ # test.parse_invalid_string
224
+ #
225
+ # @raise [ Error ] Parsing an invalid string will raise an error.
226
+ #
227
+ # @since 4.2.0
228
+ def parse_invalid_string
229
+ klass.from_string(subject)
230
+ end
231
+
232
+ # The class of the object being tested.
233
+ #
234
+ # @example
235
+ # test.klass
236
+ #
237
+ # @return [ Class ] The object class.
238
+ #
239
+ # @since 4.2.0
240
+ def klass
241
+ @spec.klass
242
+ end
243
+
244
+ # The error class of a parse error.
245
+ #
246
+ # @example
247
+ # test.parse_error
248
+ #
249
+ # @return [ Class ] The parse error class.
250
+ #
251
+ # @since 4.2.0
252
+ def parse_error
253
+ klass::InvalidRange
254
+ end
255
+
256
+ # Whether the object can be instantiated from extended json.
257
+ #
258
+ # @example Check if an object can be instantiated from the extended json.
259
+ # test.from_ex_json?
260
+ #
261
+ # @return [ true, false ] If the object can be instantiated from
262
+ # the provided extended json.
263
+ #
264
+ # @since 4.2.0
265
+ def from_ext_json?
266
+ @ext_json && @from_ext_json
267
+ end
268
+
269
+ # Whether the object can be represented as extended json.
270
+ #
271
+ # @example Check if an object can be represented as extended json.
272
+ # test.to_ext_json?
273
+ #
274
+ # @return [ true, false ] If the object can be represented as
275
+ # extended json.
276
+ #
277
+ # @since 4.2.0
278
+ def to_ext_json?
279
+ @ext_json && @to_ext_json
280
+ end
281
+
282
+ # Whether the object can be instantiated from a string.
283
+ #
284
+ # @example Check if an object can be instantiated from a string.
285
+ # test.from_string?
286
+ #
287
+ # @return [ true, false ] If the object can be instantiated from a string.
288
+ #
289
+ # @since 4.2.0
290
+ def from_string?
291
+ @string && @from_ext_json
292
+ end
293
+
294
+ # The expected string representation of the test object.
295
+ #
296
+ # @example Get the expected String representation of the test object.
297
+ # test.expected_to_string
298
+ #
299
+ # @return [ String ] The expected string representation.
300
+ #
301
+ # @since 4.2.0
302
+ def expected_to_string
303
+ match_string || string
304
+ end
305
+
306
+ # The Ruby class to which this bson object can be converted via a helper.
307
+ #
308
+ # @example Get the native type to which this object can be converted.
309
+ # test.native_type
310
+ #
311
+ # @return [ Class ] The Ruby native type.
312
+ #
313
+ # @since 4.2.0
314
+ def native_type
315
+ klass::NATIVE_TYPE
316
+ end
317
+
318
+ # Get the object converted to an instance of the native Ruby type.
319
+ #
320
+ # @example Get a native Ruby instance.
321
+ # test.native_type_conversion
322
+ #
323
+ # @return [ Object ] An instance of the Ruby native type.
324
+ #
325
+ # @since 4.2.0
326
+ def native_type_conversion
327
+ object.send("to_#{to_snake_case(native_type)}")
328
+ end
329
+
330
+ private
331
+
332
+ def to_snake_case(string)
333
+ string.to_s.gsub(/::/, '/').
334
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
335
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
336
+ tr("-", "_").
337
+ downcase
338
+ end
339
+
340
+ def decoded_document
341
+ @document ||= (data = [ @subject ].pack('H*')
342
+ buffer = BSON::ByteBuffer.new(data)
343
+ BSON::Document.from_bson(buffer))
344
+ end
345
+ end
346
+ end
347
+ end