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.
Files changed (226) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +106 -7
  3. data/Rakefile +86 -43
  4. data/ext/bson/{native-endian.h → bson-endian.h} +14 -107
  5. data/ext/bson/bson-native.h +135 -0
  6. data/ext/bson/bytebuf.c +133 -0
  7. data/ext/bson/endian.c +117 -0
  8. data/ext/bson/extconf.rb +8 -3
  9. data/ext/bson/init.c +364 -0
  10. data/ext/bson/libbson-utf8.c +230 -0
  11. data/ext/bson/read.c +470 -0
  12. data/ext/bson/util.c +250 -0
  13. data/ext/bson/write.c +675 -0
  14. data/lib/bson/active_support.rb +19 -0
  15. data/lib/bson/array.rb +97 -30
  16. data/lib/bson/big_decimal.rb +77 -0
  17. data/lib/bson/binary.rb +510 -70
  18. data/lib/bson/boolean.rb +15 -4
  19. data/lib/bson/code.rb +25 -12
  20. data/lib/bson/code_with_scope.rb +41 -15
  21. data/lib/bson/config.rb +3 -28
  22. data/lib/bson/date.rb +16 -4
  23. data/lib/bson/date_time.rb +6 -4
  24. data/lib/bson/db_pointer.rb +110 -0
  25. data/lib/bson/dbref.rb +154 -0
  26. data/lib/bson/decimal128/builder.rb +456 -0
  27. data/lib/bson/decimal128.rb +272 -0
  28. data/lib/bson/document.rb +177 -7
  29. data/lib/bson/environment.rb +17 -2
  30. data/lib/bson/error/bson_decode_error.rb +11 -0
  31. data/lib/bson/error/ext_json_parse_error.rb +11 -0
  32. data/lib/bson/error/illegal_key.rb +23 -0
  33. data/lib/bson/error/invalid_binary_type.rb +37 -0
  34. data/lib/bson/error/invalid_dbref_argument.rb +12 -0
  35. data/lib/bson/error/invalid_decimal128_argument.rb +25 -0
  36. data/lib/bson/error/invalid_decimal128_range.rb +27 -0
  37. data/lib/bson/error/invalid_decimal128_string.rb +26 -0
  38. data/lib/bson/error/invalid_key.rb +24 -0
  39. data/lib/bson/error/invalid_object_id.rb +11 -0
  40. data/lib/bson/error/invalid_regexp_pattern.rb +13 -0
  41. data/lib/bson/error/unrepresentable_precision.rb +19 -0
  42. data/lib/bson/error/unserializable_class.rb +13 -0
  43. data/lib/bson/error/unsupported_binary_subtype.rb +12 -0
  44. data/lib/bson/error/unsupported_type.rb +11 -0
  45. data/lib/bson/error.rb +22 -0
  46. data/lib/bson/ext_json.rb +389 -0
  47. data/lib/bson/false_class.rb +6 -4
  48. data/lib/bson/float.rb +43 -7
  49. data/lib/bson/hash.rb +152 -37
  50. data/lib/bson/int32.rb +104 -6
  51. data/lib/bson/int64.rb +111 -8
  52. data/lib/bson/integer.rb +43 -9
  53. data/lib/bson/json.rb +3 -1
  54. data/lib/bson/max_key.rb +21 -10
  55. data/lib/bson/min_key.rb +21 -10
  56. data/lib/bson/nil_class.rb +7 -3
  57. data/lib/bson/object.rb +25 -17
  58. data/lib/bson/object_id.rb +98 -113
  59. data/lib/bson/open_struct.rb +59 -0
  60. data/lib/bson/regexp.rb +129 -56
  61. data/lib/bson/registry.rb +7 -10
  62. data/lib/bson/specialized.rb +8 -4
  63. data/lib/bson/string.rb +12 -32
  64. data/lib/bson/symbol.rb +107 -11
  65. data/lib/bson/time.rb +68 -7
  66. data/lib/bson/time_with_zone.rb +67 -0
  67. data/lib/bson/timestamp.rb +50 -10
  68. data/lib/bson/true_class.rb +6 -4
  69. data/lib/bson/undefined.rb +28 -2
  70. data/lib/bson/vector.rb +44 -0
  71. data/lib/bson/version.rb +6 -14
  72. data/lib/bson.rb +22 -12
  73. data/spec/README.md +14 -0
  74. data/spec/bson/array_spec.rb +38 -62
  75. data/spec/bson/big_decimal_spec.rb +328 -0
  76. data/spec/bson/binary_spec.rb +199 -53
  77. data/spec/bson/binary_uuid_spec.rb +190 -0
  78. data/spec/bson/boolean_spec.rb +2 -1
  79. data/spec/bson/byte_buffer_read_spec.rb +198 -0
  80. data/spec/bson/byte_buffer_spec.rb +122 -381
  81. data/spec/bson/byte_buffer_write_spec.rb +855 -0
  82. data/spec/bson/code_spec.rb +6 -4
  83. data/spec/bson/code_with_scope_spec.rb +6 -4
  84. data/spec/bson/config_spec.rb +1 -35
  85. data/spec/bson/date_spec.rb +2 -1
  86. data/spec/bson/date_time_spec.rb +55 -1
  87. data/spec/bson/dbref_legacy_spec.rb +186 -0
  88. data/spec/bson/dbref_spec.rb +487 -0
  89. data/spec/bson/decimal128_spec.rb +1840 -0
  90. data/spec/bson/document_as_spec.rb +61 -0
  91. data/spec/bson/document_spec.rb +205 -32
  92. data/spec/bson/ext_json_parse_spec.rb +346 -0
  93. data/spec/bson/false_class_spec.rb +9 -1
  94. data/spec/bson/float_spec.rb +42 -1
  95. data/spec/bson/hash_as_spec.rb +58 -0
  96. data/spec/bson/hash_spec.rb +318 -66
  97. data/spec/bson/int32_spec.rb +248 -1
  98. data/spec/bson/int64_spec.rb +308 -1
  99. data/spec/bson/integer_spec.rb +61 -3
  100. data/spec/bson/json_spec.rb +2 -1
  101. data/spec/bson/max_key_spec.rb +6 -4
  102. data/spec/bson/min_key_spec.rb +6 -4
  103. data/spec/bson/nil_class_spec.rb +2 -1
  104. data/spec/bson/object_id_spec.rb +95 -5
  105. data/spec/bson/object_spec.rb +3 -2
  106. data/spec/bson/open_struct_spec.rb +87 -0
  107. data/spec/bson/raw_spec.rb +594 -0
  108. data/spec/bson/regexp_spec.rb +61 -8
  109. data/spec/bson/registry_spec.rb +3 -2
  110. data/spec/bson/string_spec.rb +26 -33
  111. data/spec/bson/symbol_raw_spec.rb +70 -0
  112. data/spec/bson/symbol_spec.rb +77 -20
  113. data/spec/bson/time_spec.rb +206 -2
  114. data/spec/bson/time_with_zone_spec.rb +69 -0
  115. data/spec/bson/timestamp_spec.rb +58 -2
  116. data/spec/bson/true_class_spec.rb +9 -1
  117. data/spec/bson/undefined_spec.rb +28 -1
  118. data/spec/bson/vector_spec.rb +33 -0
  119. data/spec/bson_spec.rb +2 -1
  120. data/spec/runners/binary_vector.rb +78 -0
  121. data/spec/runners/common_driver.rb +348 -0
  122. data/spec/runners/corpus.rb +191 -0
  123. data/spec/runners/corpus_legacy.rb +248 -0
  124. data/spec/shared/LICENSE +20 -0
  125. data/spec/shared/bin/get-mongodb-download-url +17 -0
  126. data/spec/shared/bin/s3-copy +45 -0
  127. data/spec/shared/bin/s3-upload +69 -0
  128. data/spec/shared/lib/mrss/child_process_helper.rb +80 -0
  129. data/spec/shared/lib/mrss/cluster_config.rb +231 -0
  130. data/spec/shared/lib/mrss/constraints.rb +378 -0
  131. data/spec/shared/lib/mrss/docker_runner.rb +298 -0
  132. data/spec/shared/lib/mrss/eg_config_utils.rb +51 -0
  133. data/spec/shared/lib/mrss/event_subscriber.rb +210 -0
  134. data/spec/shared/lib/mrss/lite_constraints.rb +238 -0
  135. data/spec/shared/lib/mrss/release/candidate.rb +281 -0
  136. data/spec/shared/lib/mrss/release/product_data.rb +144 -0
  137. data/spec/shared/lib/mrss/server_version_registry.rb +113 -0
  138. data/spec/shared/lib/mrss/session_registry.rb +69 -0
  139. data/spec/shared/lib/mrss/session_registry_legacy.rb +60 -0
  140. data/spec/shared/lib/mrss/spec_organizer.rb +179 -0
  141. data/spec/shared/lib/mrss/utils.rb +37 -0
  142. data/spec/shared/lib/tasks/candidate.rake +64 -0
  143. data/spec/shared/share/Dockerfile.erb +251 -0
  144. data/spec/shared/share/haproxy-1.conf +16 -0
  145. data/spec/shared/share/haproxy-2.conf +17 -0
  146. data/spec/shared/shlib/config.sh +27 -0
  147. data/spec/shared/shlib/distro.sh +84 -0
  148. data/spec/shared/shlib/server.sh +423 -0
  149. data/spec/shared/shlib/set_env.sh +110 -0
  150. data/spec/spec_helper.rb +61 -1
  151. data/spec/spec_tests/binary_vector_spec.rb +82 -0
  152. data/spec/spec_tests/common_driver_spec.rb +84 -0
  153. data/spec/spec_tests/corpus_legacy_spec.rb +72 -0
  154. data/spec/spec_tests/corpus_spec.rb +134 -0
  155. data/spec/spec_tests/data/binary_vector/README.md +61 -0
  156. data/spec/spec_tests/data/binary_vector/float32.json +65 -0
  157. data/spec/spec_tests/data/binary_vector/int8.json +57 -0
  158. data/spec/spec_tests/data/binary_vector/packed_bit.json +83 -0
  159. data/spec/spec_tests/data/corpus/README.md +15 -0
  160. data/spec/spec_tests/data/corpus/array.json +49 -0
  161. data/spec/spec_tests/data/corpus/binary.json +153 -0
  162. data/spec/spec_tests/data/corpus/boolean.json +27 -0
  163. data/spec/spec_tests/data/corpus/code.json +67 -0
  164. data/spec/spec_tests/data/corpus/code_w_scope.json +78 -0
  165. data/spec/spec_tests/data/corpus/datetime.json +42 -0
  166. data/spec/spec_tests/data/corpus/dbpointer.json +56 -0
  167. data/spec/spec_tests/data/corpus/dbref.json +51 -0
  168. data/spec/spec_tests/data/corpus/decimal128-1.json +317 -0
  169. data/spec/spec_tests/data/corpus/decimal128-2.json +793 -0
  170. data/spec/spec_tests/data/corpus/decimal128-3.json +1771 -0
  171. data/spec/spec_tests/data/corpus/decimal128-4.json +165 -0
  172. data/spec/spec_tests/data/corpus/decimal128-5.json +402 -0
  173. data/spec/spec_tests/data/corpus/decimal128-6.json +131 -0
  174. data/spec/spec_tests/data/corpus/decimal128-7.json +327 -0
  175. data/spec/spec_tests/data/corpus/document.json +60 -0
  176. data/spec/spec_tests/data/corpus/double.json +87 -0
  177. data/spec/spec_tests/data/corpus/int32.json +43 -0
  178. data/spec/spec_tests/data/corpus/int64.json +43 -0
  179. data/spec/spec_tests/data/corpus/maxkey.json +12 -0
  180. data/spec/spec_tests/data/corpus/minkey.json +12 -0
  181. data/spec/spec_tests/data/corpus/multi-type-deprecated.json +15 -0
  182. data/spec/spec_tests/data/corpus/multi-type.json +11 -0
  183. data/spec/spec_tests/data/corpus/null.json +12 -0
  184. data/spec/spec_tests/data/corpus/oid.json +28 -0
  185. data/spec/spec_tests/data/corpus/regex.json +65 -0
  186. data/spec/spec_tests/data/corpus/string.json +72 -0
  187. data/spec/spec_tests/data/corpus/symbol.json +80 -0
  188. data/spec/spec_tests/data/corpus/timestamp.json +34 -0
  189. data/spec/spec_tests/data/corpus/top.json +262 -0
  190. data/spec/spec_tests/data/corpus/undefined.json +15 -0
  191. data/spec/spec_tests/data/corpus_legacy/array.json +49 -0
  192. data/spec/spec_tests/data/corpus_legacy/binary.json +69 -0
  193. data/spec/spec_tests/data/corpus_legacy/boolean.json +27 -0
  194. data/spec/spec_tests/data/corpus_legacy/code.json +67 -0
  195. data/spec/spec_tests/data/corpus_legacy/code_w_scope.json +78 -0
  196. data/spec/spec_tests/data/corpus_legacy/document.json +36 -0
  197. data/spec/spec_tests/data/corpus_legacy/double.json +69 -0
  198. data/spec/spec_tests/data/corpus_legacy/failures/datetime.json +31 -0
  199. data/spec/spec_tests/data/corpus_legacy/failures/dbpointer.json +42 -0
  200. data/spec/spec_tests/data/corpus_legacy/failures/int64.json +38 -0
  201. data/spec/spec_tests/data/corpus_legacy/failures/symbol.json +62 -0
  202. data/spec/spec_tests/data/corpus_legacy/int32.json +38 -0
  203. data/spec/spec_tests/data/corpus_legacy/maxkey.json +12 -0
  204. data/spec/spec_tests/data/corpus_legacy/minkey.json +12 -0
  205. data/spec/spec_tests/data/corpus_legacy/null.json +12 -0
  206. data/spec/spec_tests/data/corpus_legacy/oid.json +28 -0
  207. data/spec/spec_tests/data/corpus_legacy/regex.json +37 -0
  208. data/spec/spec_tests/data/corpus_legacy/string.json +67 -0
  209. data/spec/spec_tests/data/corpus_legacy/timestamp.json +18 -0
  210. data/spec/spec_tests/data/corpus_legacy/top.json +62 -0
  211. data/spec/spec_tests/data/corpus_legacy/undefined.json +13 -0
  212. data/spec/spec_tests/data/decimal128/decimal128-1.json +363 -0
  213. data/spec/spec_tests/data/decimal128/decimal128-2.json +793 -0
  214. data/spec/spec_tests/data/decimal128/decimal128-3.json +1771 -0
  215. data/spec/spec_tests/data/decimal128/decimal128-4.json +165 -0
  216. data/spec/spec_tests/data/decimal128/decimal128-5.json +402 -0
  217. data/spec/spec_tests/data/decimal128/decimal128-6.json +131 -0
  218. data/spec/spec_tests/data/decimal128/decimal128-7.json +327 -0
  219. data/spec/support/shared_examples.rb +32 -11
  220. data/spec/support/spec_config.rb +17 -0
  221. data/spec/support/utils.rb +58 -0
  222. metadata +284 -45
  223. checksums.yaml.gz.sig +0 -3
  224. data/ext/bson/native.c +0 -722
  225. data.tar.gz.sig +0 -0
  226. metadata.gz.sig +0 -0
@@ -0,0 +1,594 @@
1
+ # rubocop:todo all
2
+ require 'spec_helper'
3
+
4
+ describe Regexp::Raw do
5
+
6
+ let(:pattern) { '\W+' }
7
+ let(:options) { '' }
8
+ let(:bson) { "#{pattern}#{BSON::NULL_BYTE}#{options}#{BSON::NULL_BYTE}" }
9
+
10
+ describe "#as_json" do
11
+
12
+ let(:object) do
13
+ described_class.new(pattern, 'im')
14
+ end
15
+
16
+ it "returns the legacy serialization including regex pattern and options" do
17
+ expect(object.as_json).to eq({ "$regex" => "\\W+", "$options" => "im" })
18
+ end
19
+
20
+ it_behaves_like "a JSON serializable object"
21
+ end
22
+
23
+ describe '#as_extended_json' do
24
+
25
+ let(:object) do
26
+ described_class.new(pattern, 'im')
27
+ end
28
+
29
+ context 'legacy mode' do
30
+ it "returns the legacy serialization including regex pattern and options" do
31
+ expect(object.as_extended_json(mode: :legacy)).to eq({ "$regex" => "\\W+", "$options" => "im" })
32
+ end
33
+ end
34
+
35
+ context 'canonical/relaxed mode' do
36
+ it "returns the extended json 2.0 serialization" do
37
+ expect(object.as_extended_json).to eq(
38
+ "$regularExpression" => {'pattern' => "\\W+", "options" => "im"}
39
+ )
40
+ end
41
+ end
42
+ end
43
+
44
+ describe "#to_bson/#from_bson" do
45
+
46
+ let(:options) { 'ilmsux' }
47
+ let(:obj) { described_class.new(pattern, options) }
48
+ let(:type) { 11.chr }
49
+ let(:bson) { "#{pattern}#{BSON::NULL_BYTE}#{options}#{BSON::NULL_BYTE}" }
50
+
51
+ let(:klass) { ::Regexp }
52
+
53
+ it_behaves_like "a bson element"
54
+ it_behaves_like "a serializable bson element"
55
+ it_behaves_like "a deserializable bson element"
56
+ end
57
+
58
+ describe "#initialize" do
59
+
60
+ let(:object) do
61
+ described_class.new(pattern, options)
62
+ end
63
+
64
+ context "when options are not passed" do
65
+
66
+ it "sets the options on the raw regex" do
67
+ expect(object.options). to eq(options)
68
+ end
69
+
70
+ context "When the raw regexp is compiled" do
71
+
72
+ let(:regexp) do
73
+ object.compile
74
+ end
75
+
76
+ it "sets the options on the compiled regexp object" do
77
+ expect(regexp.options).to eq(0)
78
+ end
79
+ end
80
+ end
81
+
82
+ context "when options are passed" do
83
+
84
+ context "when options are an Integer" do
85
+
86
+ let(:options) { ::Regexp::EXTENDED }
87
+
88
+ it "raises an error" do
89
+ expect do
90
+ object
91
+ end.to raise_error(ArgumentError, /Regexp options must be a String or Symbol/)
92
+ end
93
+ end
94
+
95
+ context "when options are a String" do
96
+
97
+ let(:options) { 'x' }
98
+
99
+ it "sets the options on the raw regex" do
100
+ expect(object.options). to eq(options)
101
+ end
102
+
103
+ context "When the raw regexp is compiled" do
104
+
105
+ let(:regexp) do
106
+ object.compile
107
+ end
108
+
109
+ it "sets the options on the compiled regexp object" do
110
+ expect(regexp.options).to eq(::Regexp::EXTENDED)
111
+ end
112
+ end
113
+ end
114
+ end
115
+
116
+ context 'when options are not passed' do
117
+
118
+ let(:object) do
119
+ described_class.new(pattern)
120
+ end
121
+
122
+ it "sets no options on the raw regex" do
123
+ expect(object.options). to eq('')
124
+ end
125
+
126
+ context "When the raw regexp is compiled" do
127
+
128
+ let(:regexp) do
129
+ object.compile
130
+ end
131
+
132
+ it "sets the options on the compiled regexp object" do
133
+ expect(regexp.options).to eq(0)
134
+ end
135
+ end
136
+ end
137
+ end
138
+
139
+ describe "#from_bson" do
140
+
141
+ let(:obj) { ::Regexp.from_bson(io) }
142
+ let(:io) { BSON::ByteBuffer.new(bson) }
143
+
144
+ it "deserializes to a Regexp::Raw object" do
145
+ expect(obj).to be_a(Regexp::Raw)
146
+ end
147
+
148
+ it "deserializes the pattern" do
149
+ expect(obj.pattern).to eq(pattern)
150
+ end
151
+
152
+ context "when there are no options" do
153
+
154
+ it "does not set any options on the raw regexp object" do
155
+ expect(obj.options).to eq(options)
156
+ end
157
+ end
158
+
159
+ context "when there are options" do
160
+
161
+ context "when there is the i ignorecase option" do
162
+
163
+ let(:options) { 'i' }
164
+
165
+ it "deserializes the pattern" do
166
+ expect(obj.pattern).to eq(pattern)
167
+ end
168
+
169
+ it "sets the i option on the raw regexp object" do
170
+ expect(obj.options).to eq(options)
171
+ end
172
+ end
173
+
174
+ context "when there is the l locale dependent option" do
175
+
176
+ let(:options) { 'l' }
177
+
178
+ it "deserializes the pattern" do
179
+ expect(obj.pattern).to eq(pattern)
180
+ end
181
+
182
+ it "sets the l option on the raw regexp object" do
183
+ expect(obj.options).to eq(options)
184
+ end
185
+ end
186
+
187
+ context "when there is the m multiline option" do
188
+
189
+ let(:options) { 'm' }
190
+
191
+ it "deserializes the pattern" do
192
+ expect(obj.pattern).to eq(pattern)
193
+ end
194
+
195
+ it "sets the m option on the raw regexp object" do
196
+ expect(obj.options).to eq(options)
197
+ end
198
+ end
199
+
200
+ context "when there is the s dotall option" do
201
+
202
+ let(:options) { 's' }
203
+
204
+ it "deserializes the pattern" do
205
+ expect(obj.pattern).to eq(pattern)
206
+ end
207
+
208
+ it "sets the s option on the raw regexp object" do
209
+ expect(obj.options).to eq(options)
210
+ end
211
+ end
212
+
213
+ context "when there is the u match unicode option" do
214
+
215
+ let(:options) { 'u' }
216
+
217
+ it "deserializes the pattern" do
218
+ expect(obj.pattern).to eq(pattern)
219
+ end
220
+
221
+ it "sets the u option on the raw regexp object" do
222
+ expect(obj.options).to eq(options)
223
+ end
224
+ end
225
+
226
+ context "when there is the x verbose option" do
227
+
228
+ let(:options) { 'x' }
229
+
230
+ it "deserializes the pattern" do
231
+ expect(obj.pattern).to eq(pattern)
232
+ end
233
+
234
+ it "sets the x option on the raw regexp object" do
235
+ expect(obj.options).to eq(options)
236
+ end
237
+ end
238
+
239
+ context "when all options are set" do
240
+
241
+ let(:options) { 'ilmsux' }
242
+
243
+ it "deserializes the pattern" do
244
+ expect(obj.pattern).to eq(pattern)
245
+ end
246
+
247
+ it "sets all options on the raw regexp object" do
248
+ expect(obj.options).to eq(options)
249
+ end
250
+ end
251
+ end
252
+ end
253
+
254
+ context "when a method is called on a Raw regexp object" do
255
+
256
+ let(:obj) { ::Regexp.from_bson(io) }
257
+ let(:io) { BSON::ByteBuffer.new(bson) }
258
+
259
+ it "forwards the method call on to the compiled Ruby Regexp object" do
260
+ expect(obj.source).to eq(pattern)
261
+ end
262
+ end
263
+
264
+ context "when respond_to? is called on the Raw Regexp object" do
265
+
266
+ let(:obj) { Regexp::Raw.new(pattern, options) }
267
+
268
+ context "when include_private is false" do
269
+
270
+ it "does not consider private methods" do
271
+ expect(obj.respond_to?(:initialize_copy)).to eq(false)
272
+ end
273
+ end
274
+
275
+ context "when include private is true" do
276
+
277
+ it "considers private methods" do
278
+ expect(obj.respond_to?(:initialize_copy, true)).to eq(true)
279
+ end
280
+ end
281
+
282
+ context "when include_private is not specified" do
283
+
284
+ it "does not consider private methods" do
285
+ expect(obj.respond_to?(:initialize_copy)).to eq(false)
286
+ end
287
+ end
288
+ end
289
+
290
+ context "#to_bson" do
291
+
292
+ let(:obj) { Regexp::Raw.new(pattern, options) }
293
+ let(:options) { '' }
294
+ let(:bson) { "#{pattern}#{BSON::NULL_BYTE}#{options}#{BSON::NULL_BYTE}" }
295
+ let(:serialized) { obj.to_bson.to_s }
296
+
297
+ it "serializes the pattern" do
298
+ expect(serialized).to eq(bson)
299
+ end
300
+
301
+ context "where there are no options" do
302
+
303
+ it "does not set any options on the bson regex object" do
304
+ expect(serialized).to eq(bson)
305
+ end
306
+ end
307
+
308
+ context "when there are options" do
309
+
310
+ context "when options are specified as an Integer" do
311
+
312
+ let(:options) { ::Regexp::EXTENDED }
313
+ let(:bson) { "#{pattern}#{BSON::NULL_BYTE}mx#{BSON::NULL_BYTE}" }
314
+
315
+ it "raises an error" do
316
+ expect do
317
+ serialized
318
+ end.to raise_error(ArgumentError, /Regexp options must be a String or Symbol/)
319
+ end
320
+ end
321
+
322
+ context "when there is the i ignorecase option" do
323
+
324
+ let(:options) { 'i' }
325
+
326
+ it "sets the option on the serialized bson object" do
327
+ expect(serialized).to eq(bson)
328
+ end
329
+ end
330
+
331
+ context "when there is the l locale dependent option" do
332
+
333
+ let(:options) { 'l' }
334
+
335
+ it "sets the option on the serialized bson object" do
336
+ expect(serialized).to eq(bson)
337
+ end
338
+ end
339
+
340
+ context "when there is the m multiline option" do
341
+
342
+ let(:options) { 'm' }
343
+
344
+ it "sets the option on the serialized bson object" do
345
+ expect(serialized).to eq(bson)
346
+ end
347
+ end
348
+
349
+ context "when there is the s dotall option" do
350
+
351
+ let(:options) { 's' }
352
+
353
+ it "sets the option on the serialized bson object" do
354
+ expect(serialized).to eq(bson)
355
+ end
356
+ end
357
+
358
+ context "when there is the u match unicode option" do
359
+
360
+ let(:options) { 'u' }
361
+
362
+ it "sets the option on the serialized bson object" do
363
+ expect(serialized).to eq(bson)
364
+ end
365
+ end
366
+
367
+ context "when there is the x verbose option" do
368
+
369
+ let(:options) { 'x' }
370
+
371
+ it "sets the option on the serialized bson object" do
372
+ expect(serialized).to eq(bson)
373
+ end
374
+ end
375
+
376
+ context "when all options are set" do
377
+
378
+ let(:options) { 'ilmsux' }
379
+
380
+ it "sets all options on the serialized bson object" do
381
+ expect(serialized).to eq(bson)
382
+ end
383
+
384
+ context "when the options are not provided in alphabetical order" do
385
+
386
+ let(:options) { 'mislxu' }
387
+ let(:bson) { "#{pattern}#{BSON::NULL_BYTE}ilmsux#{BSON::NULL_BYTE}" }
388
+
389
+ it "serializes the options in alphabetical order" do
390
+ expect(serialized).to eq(bson)
391
+ end
392
+ end
393
+ end
394
+ end
395
+ end
396
+
397
+ describe "#compile" do
398
+
399
+ let(:obj) { Regexp.from_bson(io) }
400
+ let(:io) { BSON::ByteBuffer.new(bson) }
401
+ let(:ruby_regexp) { obj.compile }
402
+
403
+ it "sets the pattern on the Ruby Regexp object" do
404
+ expect(obj.pattern).to eq(ruby_regexp.source)
405
+ end
406
+
407
+ context "when there are no options set" do
408
+
409
+ it "does not set any options on the Ruby Regexp object" do
410
+ expect(ruby_regexp.options).to eq(0)
411
+ end
412
+ end
413
+
414
+ context "when there are options set" do
415
+
416
+ context "when there is the i ignorecase option" do
417
+
418
+ let(:options) { 'i' }
419
+
420
+ it "sets the i option on the Ruby Regexp object" do
421
+ expect(ruby_regexp.options).to eq(::Regexp::IGNORECASE)
422
+ end
423
+ end
424
+
425
+ context "when there is the l locale dependent option" do
426
+
427
+ let(:options) { 'l' }
428
+
429
+ it "does not set an option on the Ruby Regexp object" do
430
+ expect(ruby_regexp.options).to eq(0)
431
+ end
432
+ end
433
+
434
+ context "when there is the m multiline option" do
435
+
436
+ let(:options) { 'm' }
437
+
438
+ it "does not set an option on the Ruby Regexp object" do
439
+ expect(ruby_regexp.options).to eq(0)
440
+ end
441
+ end
442
+
443
+ context "when there is the s dotall option" do
444
+
445
+ let(:options) { 's' }
446
+
447
+ # s in a bson regex maps to a Ruby Multiline Regexp option
448
+ it "sets the m option on the Ruby Regexp object" do
449
+ expect(ruby_regexp.options).to eq(::Regexp::MULTILINE)
450
+ end
451
+ end
452
+
453
+ context "when there is the u match unicode option" do
454
+
455
+ let(:options) { 'u' }
456
+
457
+ it "does not set an option on the Ruby Regexp object" do
458
+ expect(ruby_regexp.options).to eq(0)
459
+ end
460
+ end
461
+
462
+ context "when there is the x verbose option" do
463
+
464
+ let(:options) { 'x' }
465
+
466
+ it "sets the x option on the Ruby Regexp object" do
467
+ expect(ruby_regexp.options).to eq(::Regexp::EXTENDED)
468
+ end
469
+ end
470
+
471
+ context "when all options are set" do
472
+
473
+ let(:options) { 'ilmsux' }
474
+
475
+ # s in a bson regex maps to a Ruby Multiline Regexp option
476
+ it "sets the i, m, and x options on the Ruby Regexp object" do
477
+ expect(ruby_regexp.options).to eq(::Regexp::IGNORECASE | ::Regexp::MULTILINE | ::Regexp::EXTENDED)
478
+ end
479
+ end
480
+ end
481
+ end
482
+
483
+ context "when a Regexp::Raw object is roundtripped" do
484
+
485
+ let(:obj) { Regexp::Raw.new(pattern, options) }
486
+ let(:serialized) { obj.to_bson.to_s }
487
+ let(:roundtripped) { Regexp.from_bson(BSON::ByteBuffer.new(serialized)) }
488
+
489
+ it "roundtrips the pattern" do
490
+ expect(roundtripped.pattern).to eq(pattern)
491
+ end
492
+
493
+ context "when there are no options" do
494
+
495
+ let(:options) { '' }
496
+
497
+ it "does not set any options on the roundtripped Regexp::Raw object" do
498
+ expect(roundtripped.options).to eq(options)
499
+ end
500
+ end
501
+
502
+ context "when there are options set" do
503
+
504
+ context "when there is the i ignorecase option" do
505
+
506
+ let(:options) { 'i' }
507
+
508
+ it "sets the i option on the roundtripped Regexp::Raw object" do
509
+ expect(roundtripped.options).to eq(options)
510
+ end
511
+ end
512
+
513
+ context "when there is the l locale dependent option" do
514
+
515
+ let(:options) { 'l' }
516
+
517
+ it "sets the l option on the roundtripped Regexp::Raw object" do
518
+ expect(roundtripped.options).to eq(options)
519
+ end
520
+ end
521
+
522
+ context "when there is the m multiline option" do
523
+
524
+ let(:options) { 'm' }
525
+
526
+ it "sets the m option on the roundtripped Regexp::Raw object" do
527
+ expect(roundtripped.options).to eq(options)
528
+ end
529
+ end
530
+
531
+ context "when there is the s dotall option" do
532
+
533
+ let(:options) { 's' }
534
+
535
+ it "sets the s option on the roundtripped Regexp::Raw object" do
536
+ expect(roundtripped.options).to eq(options)
537
+ end
538
+ end
539
+
540
+ context "when there is the u match unicode option" do
541
+
542
+ let(:options) { 'u' }
543
+
544
+ it "sets the u option on the roundtripped Regexp::Raw object" do
545
+ expect(roundtripped.options).to eq(options)
546
+ end
547
+ end
548
+
549
+ context "when there is the x verbose option" do
550
+
551
+ let(:options) { 'x' }
552
+
553
+ it "sets the x option on the roundtripped Regexp::Raw object" do
554
+ expect(roundtripped.options).to eq(options)
555
+ end
556
+ end
557
+
558
+ context "when all options are set" do
559
+
560
+ let(:options) { 'ilmsux' }
561
+
562
+ it "sets all the options on the roundtripped Regexp::Raw object" do
563
+ expect(roundtripped.options).to eq(options)
564
+ end
565
+
566
+ context "when the options are passed in not in alphabetical order" do
567
+
568
+ let(:options) { 'sumlxi' }
569
+
570
+ it "sets all the options on the roundtripped Regexp::Raw object in order" do
571
+ expect(roundtripped.options).to eq(options.chars.sort.join)
572
+ end
573
+ end
574
+ end
575
+ end
576
+ end
577
+
578
+ describe 'yaml loading' do
579
+ let(:regexp) { described_class.new('hello.world', 's') }
580
+
581
+ it 'round-trips' do
582
+ actual = if YAML.respond_to?(:unsafe_load)
583
+ # In psych >= 4.0.0 `load` is basically an alias to `safe_load`,
584
+ # which will fail here.
585
+ YAML.unsafe_load(regexp.to_yaml)
586
+ else
587
+ YAML.load(regexp.to_yaml)
588
+ end
589
+ actual.pattern.should == 'hello.world'
590
+ actual.options.should == 's'
591
+ actual.compile.should =~ "hello\nworld"
592
+ end
593
+ end
594
+ end
@@ -1,4 +1,5 @@
1
- # Copyright (C) 2009-2014 MongoDB Inc.
1
+ # rubocop:todo all
2
+ # Copyright (C) 2009-2020 MongoDB Inc.
2
3
  #
3
4
  # Licensed under the Apache License, Version 2.0 (the "License");
4
5
  # you may not use this file except in compliance with the License.
@@ -24,7 +25,7 @@ describe Regexp do
24
25
 
25
26
  it "returns the binary data plus type" do
26
27
  expect(object.as_json).to eq(
27
- { "$regex" => "\\W+", "$options" => "i" }
28
+ { "$regex" => "\\W+", "$options" => "im" }
28
29
  )
29
30
  end
30
31
 
@@ -55,9 +56,7 @@ describe Regexp do
55
56
  /\d+/
56
57
  end
57
58
 
58
- let :bson do
59
- [obj.source, BSON::NULL_BYTE, BSON::NULL_BYTE].join ''
60
- end
59
+ let(:bson) { "#{obj.source}#{BSON::NULL_BYTE}m#{BSON::NULL_BYTE}" }
61
60
 
62
61
  it_behaves_like "a serializable bson element"
63
62
 
@@ -69,7 +68,9 @@ describe Regexp do
69
68
  context "when the regexp has no options" do
70
69
 
71
70
  let(:obj) { /\d+/ }
72
- let(:bson) { "#{obj.source}#{BSON::NULL_BYTE}#{BSON::NULL_BYTE}" }
71
+ # Ruby always has a BSON regex's equivalent of multiline on
72
+ # http://www.regular-expressions.info/modifiers.html
73
+ let(:bson) { "#{obj.source}#{BSON::NULL_BYTE}m#{BSON::NULL_BYTE}" }
73
74
 
74
75
  it_behaves_like "a serializable bson element"
75
76
 
@@ -83,7 +84,7 @@ describe Regexp do
83
84
  context "when ignoring case" do
84
85
 
85
86
  let(:obj) { /\W+/i }
86
- let(:bson) { "#{obj.source}#{BSON::NULL_BYTE}i#{BSON::NULL_BYTE}" }
87
+ let(:bson) { "#{obj.source}#{BSON::NULL_BYTE}im#{BSON::NULL_BYTE}" }
87
88
 
88
89
  it_behaves_like "a serializable bson element"
89
90
 
@@ -107,7 +108,7 @@ describe Regexp do
107
108
  context "when matching extended" do
108
109
 
109
110
  let(:obj) { /\W+/x }
110
- let(:bson) { "#{obj.source}#{BSON::NULL_BYTE}x#{BSON::NULL_BYTE}" }
111
+ let(:bson) { "#{obj.source}#{BSON::NULL_BYTE}mx#{BSON::NULL_BYTE}" }
111
112
 
112
113
  it_behaves_like "a serializable bson element"
113
114
 
@@ -127,6 +128,58 @@ describe Regexp do
127
128
  expect(result).to eq(obj)
128
129
  end
129
130
  end
131
+
132
+ context "when the regexp options contains a null byte" do
133
+
134
+ let(:regexp) do
135
+ Regexp::Raw.new("pattern", "options\x00")
136
+ end
137
+
138
+ it "raises an error" do
139
+ expect do
140
+ regexp
141
+ end.to raise_error(BSON::Error::InvalidRegexpPattern, /Regexp options cannot contain a null byte/)
142
+ end
143
+ end
144
+
145
+ context "when the regexp options is an integer" do
146
+
147
+ let(:regexp) do
148
+ Regexp::Raw.new("pattern", 1)
149
+ end
150
+
151
+ it "raises an error" do
152
+ expect do
153
+ regexp
154
+ end.to raise_error(ArgumentError, /Regexp options must be a String or Symbol/)
155
+ end
156
+ end
157
+
158
+ context "when the regexp options is an invalid type" do
159
+
160
+ let(:regexp) do
161
+ Regexp::Raw.new("pattern", [2])
162
+ end
163
+
164
+ it "raises an error" do
165
+ expect do
166
+ regexp
167
+ end.to raise_error(ArgumentError, /Regexp options must be a String or Symbol/)
168
+ end
169
+ end
170
+ end
171
+
172
+ context "when the pattern contains a null byte" do
173
+
174
+ let(:regexp) do
175
+ Regexp::Raw.new("pattern\x00", "options")
176
+ end
177
+
178
+ it "raises an error" do
179
+ expect do
180
+ regexp
181
+ end.to raise_error(BSON::Error::InvalidRegexpPattern, /Regexp pattern cannot contain a null byte/)
182
+ end
130
183
  end
131
184
  end
132
185
  end
@@ -1,4 +1,5 @@
1
- # Copyright (C) 2009-2014 MongoDB Inc.
1
+ # rubocop:todo all
2
+ # Copyright (C) 2009-2020 MongoDB Inc.
2
3
  #
3
4
  # Licensed under the Apache License, Version 2.0 (the "License");
4
5
  # you may not use this file except in compliance with the License.
@@ -38,7 +39,7 @@ describe BSON::Registry do
38
39
  it "raises an error" do
39
40
  expect {
40
41
  described_class.get(25.chr, "field")
41
- }.to raise_error(BSON::Registry::UnsupportedType)
42
+ }.to raise_error(BSON::Error::UnsupportedType)
42
43
  end
43
44
  end
44
45
  end