bson 4.1.1 → 4.2.0.rc0
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 +0 -0
- data.tar.gz.sig +0 -0
- data/Rakefile +18 -3
- data/ext/bson/{native.c → bson_native.c} +48 -8
- data/ext/bson/extconf.rb +1 -1
- data/ext/bson/native-endian.h +1 -1
- data/lib/bson.rb +3 -1
- data/lib/bson/config.rb +1 -1
- data/lib/bson/decimal128.rb +318 -0
- data/lib/bson/decimal128/builder.rb +448 -0
- data/lib/bson/document.rb +2 -2
- data/lib/bson/environment.rb +13 -1
- data/lib/bson/int32.rb +46 -0
- data/lib/bson/int64.rb +46 -0
- data/lib/bson/max_key.rb +1 -1
- data/lib/bson/min_key.rb +1 -1
- data/lib/bson/object_id.rb +2 -1
- data/lib/bson/open_struct.rb +57 -0
- data/lib/bson/regexp.rb +1 -1
- data/lib/bson/registry.rb +1 -1
- data/lib/bson/version.rb +2 -2
- data/spec/bson/decimal128_spec.rb +1583 -0
- data/spec/bson/document_spec.rb +1 -1
- data/spec/bson/driver_bson_spec.rb +77 -0
- data/spec/bson/int32_spec.rb +58 -0
- data/spec/bson/int64_spec.rb +58 -0
- data/spec/bson/open_struct_spec.rb +144 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/support/common_driver.rb +347 -0
- data/spec/support/driver-spec-tests/decimal128/decimal128-1.json +363 -0
- data/spec/support/driver-spec-tests/decimal128/decimal128-2.json +793 -0
- data/spec/support/driver-spec-tests/decimal128/decimal128-3.json +1771 -0
- data/spec/support/driver-spec-tests/decimal128/decimal128-4.json +165 -0
- data/spec/support/driver-spec-tests/decimal128/decimal128-5.json +402 -0
- data/spec/support/driver-spec-tests/decimal128/decimal128-6.json +131 -0
- data/spec/support/driver-spec-tests/decimal128/decimal128-7.json +327 -0
- metadata +29 -4
- metadata.gz.sig +0 -0
data/spec/bson/document_spec.rb
CHANGED
@@ -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
|
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
|
data/spec/bson/int32_spec.rb
CHANGED
@@ -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
|
data/spec/bson/int64_spec.rb
CHANGED
@@ -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
|
data/spec/spec_helper.rb
CHANGED
@@ -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
|