bson 4.1.1 → 5.2.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 +5 -5
- data/README.md +106 -7
- data/Rakefile +86 -43
- data/ext/bson/{native-endian.h → bson-endian.h} +14 -107
- data/ext/bson/bson-native.h +135 -0
- data/ext/bson/bytebuf.c +133 -0
- data/ext/bson/endian.c +117 -0
- data/ext/bson/extconf.rb +8 -3
- data/ext/bson/init.c +364 -0
- data/ext/bson/libbson-utf8.c +230 -0
- data/ext/bson/read.c +470 -0
- data/ext/bson/util.c +250 -0
- data/ext/bson/write.c +675 -0
- data/lib/bson/active_support.rb +19 -0
- data/lib/bson/array.rb +97 -30
- data/lib/bson/big_decimal.rb +77 -0
- data/lib/bson/binary.rb +510 -70
- data/lib/bson/boolean.rb +15 -4
- data/lib/bson/code.rb +25 -12
- data/lib/bson/code_with_scope.rb +41 -15
- data/lib/bson/config.rb +3 -28
- data/lib/bson/date.rb +16 -4
- data/lib/bson/date_time.rb +6 -4
- data/lib/bson/db_pointer.rb +110 -0
- data/lib/bson/dbref.rb +154 -0
- data/lib/bson/decimal128/builder.rb +456 -0
- data/lib/bson/decimal128.rb +272 -0
- data/lib/bson/document.rb +177 -7
- data/lib/bson/environment.rb +17 -2
- data/lib/bson/error/bson_decode_error.rb +11 -0
- data/lib/bson/error/ext_json_parse_error.rb +11 -0
- data/lib/bson/error/illegal_key.rb +23 -0
- data/lib/bson/error/invalid_binary_type.rb +37 -0
- data/lib/bson/error/invalid_dbref_argument.rb +12 -0
- data/lib/bson/error/invalid_decimal128_argument.rb +25 -0
- data/lib/bson/error/invalid_decimal128_range.rb +27 -0
- data/lib/bson/error/invalid_decimal128_string.rb +26 -0
- data/lib/bson/error/invalid_key.rb +24 -0
- data/lib/bson/error/invalid_object_id.rb +11 -0
- data/lib/bson/error/invalid_regexp_pattern.rb +13 -0
- data/lib/bson/error/unrepresentable_precision.rb +19 -0
- data/lib/bson/error/unserializable_class.rb +13 -0
- data/lib/bson/error/unsupported_binary_subtype.rb +12 -0
- data/lib/bson/error/unsupported_type.rb +11 -0
- data/lib/bson/error.rb +22 -0
- data/lib/bson/ext_json.rb +389 -0
- data/lib/bson/false_class.rb +6 -4
- data/lib/bson/float.rb +43 -7
- data/lib/bson/hash.rb +152 -37
- data/lib/bson/int32.rb +104 -6
- data/lib/bson/int64.rb +111 -8
- data/lib/bson/integer.rb +43 -9
- data/lib/bson/json.rb +3 -1
- data/lib/bson/max_key.rb +21 -10
- data/lib/bson/min_key.rb +21 -10
- data/lib/bson/nil_class.rb +7 -3
- data/lib/bson/object.rb +25 -17
- data/lib/bson/object_id.rb +98 -113
- data/lib/bson/open_struct.rb +59 -0
- data/lib/bson/regexp.rb +129 -56
- data/lib/bson/registry.rb +7 -10
- data/lib/bson/specialized.rb +8 -4
- data/lib/bson/string.rb +12 -32
- data/lib/bson/symbol.rb +107 -11
- data/lib/bson/time.rb +68 -7
- data/lib/bson/time_with_zone.rb +67 -0
- data/lib/bson/timestamp.rb +50 -10
- data/lib/bson/true_class.rb +6 -4
- data/lib/bson/undefined.rb +28 -2
- data/lib/bson/vector.rb +44 -0
- data/lib/bson/version.rb +6 -14
- data/lib/bson.rb +22 -12
- data/spec/README.md +14 -0
- data/spec/bson/array_spec.rb +38 -62
- data/spec/bson/big_decimal_spec.rb +328 -0
- data/spec/bson/binary_spec.rb +199 -53
- data/spec/bson/binary_uuid_spec.rb +190 -0
- data/spec/bson/boolean_spec.rb +2 -1
- data/spec/bson/byte_buffer_read_spec.rb +198 -0
- data/spec/bson/byte_buffer_spec.rb +122 -381
- data/spec/bson/byte_buffer_write_spec.rb +855 -0
- data/spec/bson/code_spec.rb +6 -4
- data/spec/bson/code_with_scope_spec.rb +6 -4
- data/spec/bson/config_spec.rb +1 -35
- data/spec/bson/date_spec.rb +2 -1
- data/spec/bson/date_time_spec.rb +55 -1
- data/spec/bson/dbref_legacy_spec.rb +186 -0
- data/spec/bson/dbref_spec.rb +487 -0
- data/spec/bson/decimal128_spec.rb +1840 -0
- data/spec/bson/document_as_spec.rb +61 -0
- data/spec/bson/document_spec.rb +205 -32
- data/spec/bson/ext_json_parse_spec.rb +346 -0
- data/spec/bson/false_class_spec.rb +9 -1
- data/spec/bson/float_spec.rb +42 -1
- data/spec/bson/hash_as_spec.rb +58 -0
- data/spec/bson/hash_spec.rb +318 -66
- data/spec/bson/int32_spec.rb +248 -1
- data/spec/bson/int64_spec.rb +308 -1
- data/spec/bson/integer_spec.rb +61 -3
- data/spec/bson/json_spec.rb +2 -1
- data/spec/bson/max_key_spec.rb +6 -4
- data/spec/bson/min_key_spec.rb +6 -4
- data/spec/bson/nil_class_spec.rb +2 -1
- data/spec/bson/object_id_spec.rb +95 -5
- data/spec/bson/object_spec.rb +3 -2
- data/spec/bson/open_struct_spec.rb +87 -0
- data/spec/bson/raw_spec.rb +594 -0
- data/spec/bson/regexp_spec.rb +61 -8
- data/spec/bson/registry_spec.rb +3 -2
- data/spec/bson/string_spec.rb +26 -33
- data/spec/bson/symbol_raw_spec.rb +70 -0
- data/spec/bson/symbol_spec.rb +77 -20
- data/spec/bson/time_spec.rb +206 -2
- data/spec/bson/time_with_zone_spec.rb +69 -0
- data/spec/bson/timestamp_spec.rb +58 -2
- data/spec/bson/true_class_spec.rb +9 -1
- data/spec/bson/undefined_spec.rb +28 -1
- data/spec/bson/vector_spec.rb +33 -0
- data/spec/bson_spec.rb +2 -1
- data/spec/runners/binary_vector.rb +78 -0
- data/spec/runners/common_driver.rb +348 -0
- data/spec/runners/corpus.rb +191 -0
- data/spec/runners/corpus_legacy.rb +248 -0
- data/spec/shared/LICENSE +20 -0
- data/spec/shared/bin/get-mongodb-download-url +17 -0
- data/spec/shared/bin/s3-copy +45 -0
- data/spec/shared/bin/s3-upload +69 -0
- data/spec/shared/lib/mrss/child_process_helper.rb +80 -0
- data/spec/shared/lib/mrss/cluster_config.rb +231 -0
- data/spec/shared/lib/mrss/constraints.rb +378 -0
- data/spec/shared/lib/mrss/docker_runner.rb +298 -0
- data/spec/shared/lib/mrss/eg_config_utils.rb +51 -0
- data/spec/shared/lib/mrss/event_subscriber.rb +210 -0
- data/spec/shared/lib/mrss/lite_constraints.rb +238 -0
- data/spec/shared/lib/mrss/release/candidate.rb +281 -0
- data/spec/shared/lib/mrss/release/product_data.rb +144 -0
- data/spec/shared/lib/mrss/server_version_registry.rb +113 -0
- data/spec/shared/lib/mrss/session_registry.rb +69 -0
- data/spec/shared/lib/mrss/session_registry_legacy.rb +60 -0
- data/spec/shared/lib/mrss/spec_organizer.rb +179 -0
- data/spec/shared/lib/mrss/utils.rb +37 -0
- data/spec/shared/lib/tasks/candidate.rake +64 -0
- data/spec/shared/share/Dockerfile.erb +251 -0
- data/spec/shared/share/haproxy-1.conf +16 -0
- data/spec/shared/share/haproxy-2.conf +17 -0
- data/spec/shared/shlib/config.sh +27 -0
- data/spec/shared/shlib/distro.sh +84 -0
- data/spec/shared/shlib/server.sh +423 -0
- data/spec/shared/shlib/set_env.sh +110 -0
- data/spec/spec_helper.rb +61 -1
- data/spec/spec_tests/binary_vector_spec.rb +82 -0
- data/spec/spec_tests/common_driver_spec.rb +84 -0
- data/spec/spec_tests/corpus_legacy_spec.rb +72 -0
- data/spec/spec_tests/corpus_spec.rb +134 -0
- data/spec/spec_tests/data/binary_vector/README.md +61 -0
- data/spec/spec_tests/data/binary_vector/float32.json +65 -0
- data/spec/spec_tests/data/binary_vector/int8.json +57 -0
- data/spec/spec_tests/data/binary_vector/packed_bit.json +83 -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 +153 -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 +51 -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 +165 -0
- data/spec/spec_tests/data/corpus/decimal128-5.json +402 -0
- data/spec/spec_tests/data/corpus/decimal128-6.json +131 -0
- data/spec/spec_tests/data/corpus/decimal128-7.json +327 -0
- data/spec/spec_tests/data/corpus/document.json +60 -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 +262 -0
- data/spec/spec_tests/data/corpus/undefined.json +15 -0
- data/spec/spec_tests/data/corpus_legacy/array.json +49 -0
- data/spec/spec_tests/data/corpus_legacy/binary.json +69 -0
- data/spec/spec_tests/data/corpus_legacy/boolean.json +27 -0
- data/spec/spec_tests/data/corpus_legacy/code.json +67 -0
- data/spec/spec_tests/data/corpus_legacy/code_w_scope.json +78 -0
- data/spec/spec_tests/data/corpus_legacy/document.json +36 -0
- data/spec/spec_tests/data/corpus_legacy/double.json +69 -0
- data/spec/spec_tests/data/corpus_legacy/failures/datetime.json +31 -0
- data/spec/spec_tests/data/corpus_legacy/failures/dbpointer.json +42 -0
- data/spec/spec_tests/data/corpus_legacy/failures/int64.json +38 -0
- data/spec/spec_tests/data/corpus_legacy/failures/symbol.json +62 -0
- data/spec/spec_tests/data/corpus_legacy/int32.json +38 -0
- data/spec/spec_tests/data/corpus_legacy/maxkey.json +12 -0
- data/spec/spec_tests/data/corpus_legacy/minkey.json +12 -0
- data/spec/spec_tests/data/corpus_legacy/null.json +12 -0
- data/spec/spec_tests/data/corpus_legacy/oid.json +28 -0
- data/spec/spec_tests/data/corpus_legacy/regex.json +37 -0
- data/spec/spec_tests/data/corpus_legacy/string.json +67 -0
- data/spec/spec_tests/data/corpus_legacy/timestamp.json +18 -0
- data/spec/spec_tests/data/corpus_legacy/top.json +62 -0
- data/spec/spec_tests/data/corpus_legacy/undefined.json +13 -0
- data/spec/spec_tests/data/decimal128/decimal128-1.json +363 -0
- data/spec/spec_tests/data/decimal128/decimal128-2.json +793 -0
- data/spec/spec_tests/data/decimal128/decimal128-3.json +1771 -0
- data/spec/spec_tests/data/decimal128/decimal128-4.json +165 -0
- data/spec/spec_tests/data/decimal128/decimal128-5.json +402 -0
- data/spec/spec_tests/data/decimal128/decimal128-6.json +131 -0
- data/spec/spec_tests/data/decimal128/decimal128-7.json +327 -0
- data/spec/support/shared_examples.rb +32 -11
- data/spec/support/spec_config.rb +17 -0
- data/spec/support/utils.rb +58 -0
- metadata +284 -45
- checksums.yaml.gz.sig +0 -3
- data/ext/bson/native.c +0 -722
- data.tar.gz.sig +0 -0
- metadata.gz.sig +0 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# rubocop:todo all
|
|
2
|
+
# Copyright (C) 2021 MongoDB Inc.
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
require "spec_helper"
|
|
17
|
+
|
|
18
|
+
# BSON::Document ActiveSupport extensions
|
|
19
|
+
describe BSON::Document do
|
|
20
|
+
require_active_support
|
|
21
|
+
|
|
22
|
+
describe '#symbolize_keys' do
|
|
23
|
+
context 'string keys' do
|
|
24
|
+
let(:doc) do
|
|
25
|
+
described_class.new('foo' => 'bar')
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it 'works correctly' do
|
|
29
|
+
doc.symbolize_keys.should == {foo: 'bar'}
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
describe '#symbolize_keys!' do
|
|
35
|
+
context 'string keys' do
|
|
36
|
+
let(:doc) do
|
|
37
|
+
described_class.new('foo' => 'bar')
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it 'raises ArgumentError' do
|
|
41
|
+
lambda do
|
|
42
|
+
doc.symbolize_keys!
|
|
43
|
+
end.should raise_error(ArgumentError, /symbolize_keys! is not supported on BSON::Document instances/)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
describe '#deep_symbolize_keys!' do
|
|
49
|
+
context 'string keys' do
|
|
50
|
+
let(:doc) do
|
|
51
|
+
described_class.new('foo' => 'bar')
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it 'raises ArgumentError' do
|
|
55
|
+
expect do
|
|
56
|
+
doc.deep_symbolize_keys!
|
|
57
|
+
end.to output(/\[DEPRECATION\] `deep_symbolize_keys!` is not supported on BSON::Document instances./).to_stderr
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
data/spec/bson/document_spec.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# rubocop:todo all
|
|
2
2
|
|
|
3
|
-
# Copyright (C) 2009-
|
|
3
|
+
# Copyright (C) 2009-2020 MongoDB Inc.
|
|
4
4
|
#
|
|
5
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
6
|
# you may not use this file except in compliance with the License.
|
|
@@ -49,6 +49,68 @@ describe BSON::Document do
|
|
|
49
49
|
end
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
+
describe "#fetch" do
|
|
53
|
+
|
|
54
|
+
let(:document) do
|
|
55
|
+
described_class["key", "value", "key2", "value"]
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
context "when provided string keys" do
|
|
59
|
+
|
|
60
|
+
it "returns the value" do
|
|
61
|
+
expect(document.fetch("key")).to eq("value")
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
context "when provided symbol keys" do
|
|
66
|
+
|
|
67
|
+
it "returns the value" do
|
|
68
|
+
expect(document.fetch(:key)).to eq("value")
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
context "when key does not exist" do
|
|
73
|
+
|
|
74
|
+
it "raises KeyError" do
|
|
75
|
+
expect do
|
|
76
|
+
document.fetch(:non_existent_key)
|
|
77
|
+
end.to raise_exception(KeyError)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
context "and default value is provided" do
|
|
81
|
+
|
|
82
|
+
it "returns default value" do
|
|
83
|
+
expect(document.fetch(:non_existent_key, false)).to eq(false)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
context "and block is passed" do
|
|
88
|
+
|
|
89
|
+
it "returns result of the block" do
|
|
90
|
+
expect(document.fetch(:non_existent_key, &:to_s))
|
|
91
|
+
.to eq("non_existent_key")
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
context "when key exists" do
|
|
97
|
+
|
|
98
|
+
context "and default value is provided" do
|
|
99
|
+
|
|
100
|
+
it "returns the value" do
|
|
101
|
+
expect(document.fetch(:key, "other")).to eq("value")
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
context "and block is passed" do
|
|
106
|
+
|
|
107
|
+
it "returns the value" do
|
|
108
|
+
expect(document.fetch(:key, &:to_s)).to eq("value")
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
52
114
|
describe "#[]" do
|
|
53
115
|
|
|
54
116
|
let(:document) do
|
|
@@ -68,6 +130,13 @@ describe BSON::Document do
|
|
|
68
130
|
expect(document[:key]).to eq("value")
|
|
69
131
|
end
|
|
70
132
|
end
|
|
133
|
+
|
|
134
|
+
context "when key does not exist" do
|
|
135
|
+
|
|
136
|
+
it "returns nil" do
|
|
137
|
+
expect(document[:non_existent_key]).to be nil
|
|
138
|
+
end
|
|
139
|
+
end
|
|
71
140
|
end
|
|
72
141
|
|
|
73
142
|
describe "#[]=" do
|
|
@@ -94,8 +163,108 @@ describe BSON::Document do
|
|
|
94
163
|
it "sets the value" do
|
|
95
164
|
expect(doc[key]).to eq(val)
|
|
96
165
|
end
|
|
166
|
+
|
|
167
|
+
context 'when value is a hash' do
|
|
168
|
+
let(:val) do
|
|
169
|
+
{'foo' => {'bar' => 'baz'}}
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
it 'converts value to indifferent access' do
|
|
173
|
+
expect(doc[key][:foo][:bar]).to eq('baz')
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
context 'when value is an array with hash element' do
|
|
178
|
+
let(:val) do
|
|
179
|
+
[42, {'foo' => {'bar' => 'baz'}}]
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
it 'converts hash element to indifferent access' do
|
|
183
|
+
expect(doc[key][1][:foo][:bar]).to eq('baz')
|
|
184
|
+
end
|
|
185
|
+
end
|
|
97
186
|
end
|
|
98
187
|
|
|
188
|
+
if described_class.instance_methods.include?(:dig)
|
|
189
|
+
describe "#dig" do
|
|
190
|
+
let(:document) do
|
|
191
|
+
described_class.new("key1" => { :key2 => "value" })
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
context "when provided string keys" do
|
|
195
|
+
|
|
196
|
+
it "returns the value" do
|
|
197
|
+
expect(document.dig("key1", "key2")).to eq("value")
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
context "when provided symbol keys" do
|
|
202
|
+
|
|
203
|
+
it "returns the value" do
|
|
204
|
+
expect(document.dig(:key1, :key2)).to eq("value")
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
if described_class.instance_methods.include?(:slice)
|
|
211
|
+
describe "#slice" do
|
|
212
|
+
let(:document) do
|
|
213
|
+
described_class.new("key1" => "value1", key2: "value2")
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
context "when provided string keys" do
|
|
217
|
+
|
|
218
|
+
it "is a BSON Document" do
|
|
219
|
+
expect(document.slice("key1")).to be_a(BSON::Document)
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
it "returns the partial document" do
|
|
223
|
+
expect(document.slice("key1")).to contain_exactly(['key1', 'value1'])
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
context "when provided symbol keys" do
|
|
228
|
+
|
|
229
|
+
it "is a BSON Document" do
|
|
230
|
+
expect(document.slice(:key1)).to be_a(BSON::Document)
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
it "returns the partial document" do
|
|
234
|
+
expect(document.slice(:key1)).to contain_exactly(['key1', 'value1'])
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
context "when provided keys that do not exist in the document" do
|
|
239
|
+
|
|
240
|
+
it "returns only the keys that exist in the document" do
|
|
241
|
+
expect(document.slice(:key1, :key3)).to contain_exactly(['key1', 'value1'])
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
describe "#except" do
|
|
248
|
+
let(:document) do
|
|
249
|
+
described_class.new("key1" => "value1", key2: "value2")
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
context "when provided string keys" do
|
|
253
|
+
|
|
254
|
+
it "returns the partial document" do
|
|
255
|
+
expect(document.except("key1")).to contain_exactly(['key2', 'value2'])
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
context "when provided symbol keys" do
|
|
260
|
+
|
|
261
|
+
it "returns the partial document" do
|
|
262
|
+
expect(document.except(:key1)).to contain_exactly(['key2', 'value2'])
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
|
|
99
268
|
describe "#delete" do
|
|
100
269
|
|
|
101
270
|
shared_examples_for "a document with deletable pairs" do
|
|
@@ -351,7 +520,13 @@ describe BSON::Document do
|
|
|
351
520
|
context "when the document has been serialized" do
|
|
352
521
|
|
|
353
522
|
let(:deserialized) do
|
|
354
|
-
YAML.
|
|
523
|
+
if YAML.respond_to?(:unsafe_load)
|
|
524
|
+
# In psych >= 4.0.0 `load` is basically an alias to `safe_load`,
|
|
525
|
+
# which will fail here.
|
|
526
|
+
YAML.unsafe_load(YAML.dump(doc))
|
|
527
|
+
else
|
|
528
|
+
YAML.load(YAML.dump(doc))
|
|
529
|
+
end
|
|
355
530
|
end
|
|
356
531
|
|
|
357
532
|
let!(:enum) do
|
|
@@ -756,6 +931,24 @@ describe BSON::Document do
|
|
|
756
931
|
end
|
|
757
932
|
end
|
|
758
933
|
|
|
934
|
+
context "when the hash contains an array of hashes" do
|
|
935
|
+
let(:obj) do
|
|
936
|
+
described_class["key",[{"a" => 1}, {"b" => 2}]]
|
|
937
|
+
end
|
|
938
|
+
|
|
939
|
+
let(:bson) do
|
|
940
|
+
"#{45.to_bson}#{Array::BSON_TYPE}key#{BSON::NULL_BYTE}" +
|
|
941
|
+
"#{35.to_bson}"+
|
|
942
|
+
"#{BSON::Document::BSON_TYPE}0#{BSON::NULL_BYTE}#{12.to_bson}#{BSON::Int32::BSON_TYPE}a#{BSON::NULL_BYTE}#{1.to_bson}#{BSON::NULL_BYTE}" +
|
|
943
|
+
"#{BSON::Document::BSON_TYPE}1#{BSON::NULL_BYTE}#{12.to_bson}#{BSON::Int32::BSON_TYPE}b#{BSON::NULL_BYTE}#{2.to_bson}#{BSON::NULL_BYTE}" +
|
|
944
|
+
"#{BSON::NULL_BYTE}" +
|
|
945
|
+
"#{BSON::NULL_BYTE}"
|
|
946
|
+
end
|
|
947
|
+
|
|
948
|
+
it_behaves_like "a serializable bson element"
|
|
949
|
+
it_behaves_like "a deserializable bson element"
|
|
950
|
+
end
|
|
951
|
+
|
|
759
952
|
context "when the hash is a single level" do
|
|
760
953
|
|
|
761
954
|
let(:obj) do
|
|
@@ -867,51 +1060,31 @@ describe BSON::Document do
|
|
|
867
1060
|
it_behaves_like "a document able to handle utf-8"
|
|
868
1061
|
end
|
|
869
1062
|
|
|
870
|
-
context "
|
|
1063
|
+
context "given a utf-8-encodable string in another encoding" do
|
|
871
1064
|
|
|
872
1065
|
let(:string) { "gültig" }
|
|
873
1066
|
let(:document) do
|
|
874
1067
|
described_class["type", string.encode("iso-8859-1")]
|
|
875
1068
|
end
|
|
876
1069
|
|
|
877
|
-
it
|
|
878
|
-
expect {
|
|
879
|
-
document.to_bson
|
|
880
|
-
}.to raise_error(ArgumentError)
|
|
881
|
-
end
|
|
882
|
-
|
|
883
|
-
it 'converts the values', if: BSON::Environment.jruby? do
|
|
884
|
-
expect(
|
|
885
|
-
BSON::Document.from_bson(BSON::ByteBuffer.new(document.to_bson.to_s))
|
|
886
|
-
).to eq({ "type" => string })
|
|
887
|
-
end
|
|
888
|
-
end
|
|
889
|
-
|
|
890
|
-
context "when binary strings with utf-8 values exist", if: BSON::Environment.jruby? && (JRUBY_VERSION !~ /9.0/) do
|
|
891
|
-
|
|
892
|
-
let(:string) { "europäisch" }
|
|
893
|
-
let(:document) do
|
|
894
|
-
described_class["type", string.encode("binary")]
|
|
895
|
-
end
|
|
896
|
-
|
|
897
|
-
it "encodes and decodes the document properly" do
|
|
1070
|
+
it 'converts the values to utf-8' do
|
|
898
1071
|
expect(
|
|
899
1072
|
BSON::Document.from_bson(BSON::ByteBuffer.new(document.to_bson.to_s))
|
|
900
1073
|
).to eq({ "type" => string })
|
|
901
1074
|
end
|
|
902
1075
|
end
|
|
903
1076
|
|
|
904
|
-
context "
|
|
1077
|
+
context "given a binary string with utf-8 values" do
|
|
905
1078
|
|
|
906
|
-
let(:string) { "europäisch" }
|
|
1079
|
+
let(:string) { "europäisch".force_encoding('binary') }
|
|
907
1080
|
let(:document) do
|
|
908
|
-
described_class["type", string
|
|
1081
|
+
described_class["type", string]
|
|
909
1082
|
end
|
|
910
1083
|
|
|
911
|
-
it "
|
|
912
|
-
expect
|
|
913
|
-
|
|
914
|
-
|
|
1084
|
+
it "raises encoding error" do
|
|
1085
|
+
expect do
|
|
1086
|
+
document.to_bson
|
|
1087
|
+
end.to raise_error(Encoding::UndefinedConversionError, /from ASCII-8BIT to UTF-8/)
|
|
915
1088
|
end
|
|
916
1089
|
end
|
|
917
1090
|
end
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
# rubocop:todo all
|
|
2
|
+
# Copyright (C) 2020 MongoDB Inc.
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
require "spec_helper"
|
|
17
|
+
|
|
18
|
+
describe "BSON::ExtJSON.parse" do
|
|
19
|
+
|
|
20
|
+
let(:parsed) { BSON::ExtJSON.parse_obj(input) }
|
|
21
|
+
|
|
22
|
+
context 'when input is true' do
|
|
23
|
+
let(:input) { true }
|
|
24
|
+
|
|
25
|
+
it 'returns true' do
|
|
26
|
+
parsed.should == true
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
context 'when input is false' do
|
|
31
|
+
let(:input) { false }
|
|
32
|
+
|
|
33
|
+
it 'returns false' do
|
|
34
|
+
parsed.should == false
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
context 'when input is nil' do
|
|
39
|
+
let(:input) { nil }
|
|
40
|
+
|
|
41
|
+
it 'returns nil' do
|
|
42
|
+
parsed.should be nil
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
context 'when input is a string' do
|
|
47
|
+
let(:input) { 'hello' }
|
|
48
|
+
|
|
49
|
+
it 'returns the string' do
|
|
50
|
+
parsed.should == 'hello'
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
context 'when input is a BSON timestamp' do
|
|
55
|
+
let(:input) { {'$timestamp' => {'t' => 12345, 'i' => 42}} }
|
|
56
|
+
|
|
57
|
+
it 'returns a BSON::Timestamp instance' do
|
|
58
|
+
parsed.should == BSON::Timestamp.new(12345, 42)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
context 'when input is an ISO time' do
|
|
63
|
+
let(:input) { {'$date' => '1970-01-01T00:00:04Z'} }
|
|
64
|
+
|
|
65
|
+
it 'returns a Time instance ' do
|
|
66
|
+
parsed.should be_a(Time)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it 'returns a Time instance with correct value' do
|
|
70
|
+
parsed.should == Time.at(4)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it 'returns a Time instance in UTC' do
|
|
74
|
+
parsed.zone.should == 'UTC'
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
context 'when input is a Unix timestamp' do
|
|
79
|
+
let(:input) { {'$date' => {'$numberLong' => '4000'}} }
|
|
80
|
+
|
|
81
|
+
it 'returns a Time instance ' do
|
|
82
|
+
parsed.should be_a(Time)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it 'returns a Time instance with correct value' do
|
|
86
|
+
parsed.should == Time.at(4)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it 'returns a Time instance in UTC' do
|
|
90
|
+
parsed.zone.should == 'UTC'
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
context 'when input is an int32' do
|
|
95
|
+
let(:input) do
|
|
96
|
+
{'$numberInt' => '42'}
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
let(:parsed) { BSON::ExtJSON.parse_obj(input, mode: mode) }
|
|
100
|
+
|
|
101
|
+
context 'when :mode is nil' do
|
|
102
|
+
let(:mode) { nil }
|
|
103
|
+
|
|
104
|
+
it 'returns Integer instance' do
|
|
105
|
+
parsed.should be_a(Integer)
|
|
106
|
+
parsed.should == 42
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
context 'when :mode is :bson' do
|
|
111
|
+
let(:mode) { :bson }
|
|
112
|
+
|
|
113
|
+
it 'returns Integer instance' do
|
|
114
|
+
parsed.should be_a(Integer)
|
|
115
|
+
parsed.should == 42
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
context 'when input is an int64' do
|
|
121
|
+
let(:input) do
|
|
122
|
+
{'$numberLong' => '42'}
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
let(:parsed) { BSON::ExtJSON.parse_obj(input, mode: mode) }
|
|
126
|
+
|
|
127
|
+
context 'when :mode is nil' do
|
|
128
|
+
let(:mode) { nil }
|
|
129
|
+
|
|
130
|
+
it 'returns Integer instance' do
|
|
131
|
+
parsed.should be_a(Integer)
|
|
132
|
+
parsed.should == 42
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
context 'when :mode is :bson' do
|
|
137
|
+
let(:mode) { :bson }
|
|
138
|
+
|
|
139
|
+
it 'returns Int64 instance' do
|
|
140
|
+
parsed.should be_a(BSON::Int64)
|
|
141
|
+
parsed.value.should == 42
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
context 'when input is a hash' do
|
|
147
|
+
let(:input) do
|
|
148
|
+
{}
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
let(:parsed) { BSON::ExtJSON.parse_obj(input, mode: mode) }
|
|
152
|
+
let(:mode) { :bson }
|
|
153
|
+
|
|
154
|
+
context 'when mode is invalid' do
|
|
155
|
+
let(:mode) { :foo }
|
|
156
|
+
|
|
157
|
+
it 'raises an exception' do
|
|
158
|
+
lambda do
|
|
159
|
+
parsed
|
|
160
|
+
end.should raise_error(ArgumentError, /Invalid value for :mode option/)
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
context 'when it contains a string key with a null byte' do
|
|
165
|
+
let(:input) do
|
|
166
|
+
{ "key\x00" => 1 }
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
it 'raises an exception' do
|
|
170
|
+
lambda do
|
|
171
|
+
parsed
|
|
172
|
+
end.should raise_error(BSON::Error::ExtJSONParseError, /Hash key cannot contain a null byte/)
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
context 'when it contains a symbol key with a null byte' do
|
|
177
|
+
let(:input) do
|
|
178
|
+
{ "key\x00".to_sym => 1 }
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
it 'raises an exception' do
|
|
182
|
+
lambda do
|
|
183
|
+
parsed
|
|
184
|
+
end.should raise_error(BSON::Error::ExtJSONParseError, /Hash key cannot contain a null byte/)
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
context 'when it contains an integer key' do
|
|
189
|
+
let(:input) do
|
|
190
|
+
{ 0 => 1 }
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
it 'does not raises an exception' do
|
|
194
|
+
lambda do
|
|
195
|
+
parsed
|
|
196
|
+
end.should_not raise_error
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
context 'when input is a binary' do
|
|
202
|
+
let(:data) do
|
|
203
|
+
Base64.decode64("//8=")
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
context 'in current format' do
|
|
207
|
+
let(:input) do
|
|
208
|
+
{ "$binary" => { "base64"=>"//8=", "subType"=>"00" } }
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
context 'when :mode is nil' do
|
|
212
|
+
let(:mode) { nil }
|
|
213
|
+
|
|
214
|
+
it 'returns BSON::Binary instance' do
|
|
215
|
+
parsed.should be_a(BSON::Binary)
|
|
216
|
+
parsed.data.should == data
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
context 'when mode is :bson' do
|
|
221
|
+
let(:mode) { :bson }
|
|
222
|
+
|
|
223
|
+
it 'returns BSON::Binary instance' do
|
|
224
|
+
parsed.should be_a(BSON::Binary)
|
|
225
|
+
parsed.data.should == data
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
context 'in legacy format' do
|
|
231
|
+
let(:input) do
|
|
232
|
+
{ "$binary"=>"//8=", "$type"=>"00" }
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
context 'when :mode is nil' do
|
|
236
|
+
let(:mode) { nil }
|
|
237
|
+
|
|
238
|
+
it 'returns BSON::Binary instance' do
|
|
239
|
+
parsed.should be_a(BSON::Binary)
|
|
240
|
+
parsed.data.should == data
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
context 'when mode is :bson' do
|
|
245
|
+
let(:mode) { :bson }
|
|
246
|
+
|
|
247
|
+
it 'returns BSON::Binary instance' do
|
|
248
|
+
parsed.should be_a(BSON::Binary)
|
|
249
|
+
parsed.data.should == data
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
context 'when input is a regex' do
|
|
256
|
+
let(:pattern) { 'abc' }
|
|
257
|
+
let(:options) { 'im' }
|
|
258
|
+
|
|
259
|
+
context 'in current format' do
|
|
260
|
+
let(:input) do
|
|
261
|
+
{ "$regularExpression" => { "pattern" => pattern, "options" => options } }
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
context 'when :mode is nil' do
|
|
265
|
+
let(:mode) { nil }
|
|
266
|
+
|
|
267
|
+
it 'returns a BSON::Regexp::Raw instance' do
|
|
268
|
+
parsed.should be_a(BSON::Regexp::Raw)
|
|
269
|
+
parsed.pattern.should == pattern
|
|
270
|
+
parsed.options.should == options
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
context 'when :mode is :bson' do
|
|
275
|
+
let(:mode) { :bson }
|
|
276
|
+
|
|
277
|
+
it 'returns a BSON::Regexp::Raw instance' do
|
|
278
|
+
parsed.should be_a(BSON::Regexp::Raw)
|
|
279
|
+
parsed.pattern.should == pattern
|
|
280
|
+
parsed.options.should == options
|
|
281
|
+
end
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
context 'in legacy format' do
|
|
286
|
+
let(:input) do
|
|
287
|
+
{ "$regex" => pattern, "$options" => options }
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
context 'when :mode is nil' do
|
|
291
|
+
let(:mode) { nil }
|
|
292
|
+
|
|
293
|
+
it 'returns a BSON::Regexp::Raw instance' do
|
|
294
|
+
parsed.should be_a(BSON::Regexp::Raw)
|
|
295
|
+
parsed.pattern.should == pattern
|
|
296
|
+
parsed.options.should == options
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
context 'when :mode is :bson' do
|
|
301
|
+
let(:mode) { :bson }
|
|
302
|
+
|
|
303
|
+
it 'returns a BSON::Regexp::Raw instance' do
|
|
304
|
+
parsed.should be_a(BSON::Regexp::Raw)
|
|
305
|
+
parsed.pattern.should == pattern
|
|
306
|
+
parsed.options.should == options
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
context 'when $regularExpression is nested in $regex' do
|
|
312
|
+
context 'with options' do
|
|
313
|
+
let(:input) do
|
|
314
|
+
{
|
|
315
|
+
"$regex" => {
|
|
316
|
+
"$regularExpression" => { "pattern" => "foo*", "options" => "" },
|
|
317
|
+
},
|
|
318
|
+
"$options" => "ix",
|
|
319
|
+
}
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
it 'parses' do
|
|
323
|
+
parsed.should == {
|
|
324
|
+
'$regex' => BSON::Regexp::Raw.new('foo*'), '$options' => 'ix'
|
|
325
|
+
}
|
|
326
|
+
end
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
context 'without options' do
|
|
330
|
+
let(:input) do
|
|
331
|
+
{
|
|
332
|
+
"$regex" => {
|
|
333
|
+
"$regularExpression" => { "pattern" => "foo*", "options" => "" },
|
|
334
|
+
},
|
|
335
|
+
}
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
it 'parses' do
|
|
339
|
+
parsed.should == {
|
|
340
|
+
'$regex' => BSON::Regexp::Raw.new('foo*'),
|
|
341
|
+
}
|
|
342
|
+
end
|
|
343
|
+
end
|
|
344
|
+
end
|
|
345
|
+
end
|
|
346
|
+
end
|