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
@@ -30,7 +30,19 @@ module BSON
30
30
  #
31
31
  # @since 2.0.0
32
32
  def jruby?
33
- defined?(JRUBY_VERSION)
33
+ @jruby ||= defined?(JRUBY_VERSION)
34
+ end
35
+
36
+ # Determine if we are using Ruby version 1.9.
37
+ #
38
+ # @example Are we running with Ruby version 1.9?
39
+ # Environment.ruby_1_9?
40
+ #
41
+ # @return [ true, false ] If the Ruby version is 1.9.
42
+ #
43
+ # @since 4.2.0
44
+ def ruby_1_9?
45
+ @ruby_1_9 ||= RUBY_VERSION < '2.0.0'
34
46
  end
35
47
  end
36
48
  end
@@ -50,6 +50,52 @@ module BSON
50
50
  buffer.get_int32
51
51
  end
52
52
 
53
+ # Instantiate a BSON Int32.
54
+ #
55
+ # @param [ Integer ] integer The 32-bit integer.
56
+ #
57
+ # @see http://bsonspec.org/#/specification
58
+ #
59
+ # @since 4.2.0
60
+ def initialize(integer)
61
+ out_of_range! unless integer.bson_int32?
62
+ @integer = integer.freeze
63
+ end
64
+
65
+ # Append the integer as encoded BSON to a ByteBuffer.
66
+ #
67
+ # @example Encoded the integer and append to a ByteBuffer.
68
+ # int32.to_bson
69
+ #
70
+ # @return [ BSON::ByteBuffer ] The buffer with the encoded integer.
71
+ #
72
+ # @see http://bsonspec.org/#/specification
73
+ #
74
+ # @since 4.2.0
75
+ def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?)
76
+ buffer.put_int32(@integer)
77
+ end
78
+
79
+ # Convert the integer to a BSON string key.
80
+ #
81
+ # @example Convert the integer to a BSON key string.
82
+ # int.to_bson_key
83
+ #
84
+ # @param [ true, false ] validating_keys If BSON should validate the key.
85
+ #
86
+ # @return [ String ] The string key.
87
+ #
88
+ # @since 4.2.0
89
+ def to_bson_key(validating_keys = Config.validating_keys?)
90
+ @integer.to_bson_key(validating_keys)
91
+ end
92
+
93
+ private
94
+
95
+ def out_of_range!
96
+ raise RangeError.new("#{self} is not a valid 4 byte integer value.")
97
+ end
98
+
53
99
  # Register this type when the module is loaded.
54
100
  #
55
101
  # @since 2.0.0
@@ -45,6 +45,52 @@ module BSON
45
45
  buffer.get_int64
46
46
  end
47
47
 
48
+ # Instantiate a BSON Int64.
49
+ #
50
+ # @param [ Integer ] integer The 64-bit integer.
51
+ #
52
+ # @see http://bsonspec.org/#/specification
53
+ #
54
+ # @since 4.2.0
55
+ def initialize(integer)
56
+ out_of_range! unless integer.bson_int64?
57
+ @integer = integer.freeze
58
+ end
59
+
60
+ # Append the integer as encoded BSON to a ByteBuffer.
61
+ #
62
+ # @example Encoded the integer and append to a ByteBuffer.
63
+ # int64.to_bson
64
+ #
65
+ # @return [ BSON::ByteBuffer ] The buffer with the encoded integer.
66
+ #
67
+ # @see http://bsonspec.org/#/specification
68
+ #
69
+ # @since 4.2.0
70
+ def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?)
71
+ buffer.put_int64(@integer)
72
+ end
73
+
74
+ # Convert the integer to a BSON string key.
75
+ #
76
+ # @example Convert the integer to a BSON key string.
77
+ # int.to_bson_key
78
+ #
79
+ # @param [ true, false ] validating_keys If BSON should validate the key.
80
+ #
81
+ # @return [ String ] The string key.
82
+ #
83
+ # @since 4.2.0
84
+ def to_bson_key(validating_keys = Config.validating_keys?)
85
+ @integer.to_bson_key(validating_keys)
86
+ end
87
+
88
+ private
89
+
90
+ def out_of_range!
91
+ raise RangeError.new("#{self} is not a valid 8 byte integer value.")
92
+ end
93
+
48
94
  # Register this type when the module is loaded.
49
95
  #
50
96
  # @since 2.0.0
@@ -41,7 +41,7 @@ module BSON
41
41
  # @example Compare with another object.
42
42
  # max_key <=> 1000
43
43
  #
44
- # @param [ Object ] The object to compare against.
44
+ # @param [ Object ] other The object to compare against.
45
45
  #
46
46
  # @return [ Integer ] Always 1.
47
47
  #
@@ -41,7 +41,7 @@ module BSON
41
41
  # @example Compare with another object.
42
42
  # min_key <=> 1000
43
43
  #
44
- # @param [ Object ] The object to compare against.
44
+ # @param [ Object ] other The object to compare against.
45
45
  #
46
46
  # @return [ Integer ] Always -1.
47
47
  #
@@ -102,6 +102,7 @@ module BSON
102
102
  def generation_time
103
103
  ::Time.at(generate_data.unpack("N")[0]).utc
104
104
  end
105
+ alias :to_time :generation_time
105
106
 
106
107
  # Get the hash value for the object id.
107
108
  #
@@ -279,7 +280,7 @@ module BSON
279
280
  # @example Is the string a legal object id?
280
281
  # BSON::ObjectId.legal?(string)
281
282
  #
282
- # @param [ String ] The string to check.
283
+ # @param [ String ] string The string to check.
283
284
  #
284
285
  # @return [ true, false ] If the string is legal.
285
286
  #
@@ -0,0 +1,57 @@
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
+ module BSON
16
+
17
+ # Injects behaviour for encoding OpenStruct objects using hashes
18
+ # to raw bytes as specified by the BSON spec.
19
+ #
20
+ # @see http://bsonspec.org/#/specification
21
+ #
22
+ # @since 4.2.0
23
+ module OpenStruct
24
+
25
+ # Get the OpenStruct as encoded BSON.
26
+ #
27
+ # @example Get the OpenStruct object as encoded BSON.
28
+ # OpenStruct.new({ "field" => "value" }).to_bson
29
+ #
30
+ # @return [ String ] The encoded string.
31
+ #
32
+ # @see http://bsonspec.org/#/specification
33
+ #
34
+ # @since 4.2.0
35
+ def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?)
36
+ if Environment.ruby_1_9?
37
+ marshal_dump.dup
38
+ else
39
+ to_h
40
+ end.to_bson(buffer, validating_keys)
41
+ end
42
+
43
+ # The BSON type for OpenStruct objects is the Hash type of 0x03.
44
+ #
45
+ # @example Get the bson type.
46
+ # struct.bson_type
47
+ #
48
+ # @return [ String ] The character 0x03.
49
+ #
50
+ # @since 4.2.0
51
+ def bson_type
52
+ ::Hash::BSON_TYPE
53
+ end
54
+ end
55
+
56
+ ::OpenStruct.send(:include, OpenStruct) if defined?(::OpenStruct)
57
+ end
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2009-2015 MongoDB Inc.
1
+ # Copyright (C) 2009-2016 MongoDB Inc.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -53,7 +53,7 @@ module BSON
53
53
  # BSON::Registry.register("\x01", Float)
54
54
  #
55
55
  # @param [ String ] byte The single byte.
56
- # @param [ Class ] The class the byte maps to.
56
+ # @param [ Class ] type The class the byte maps to.
57
57
  #
58
58
  # @return [ Class ] The class.
59
59
  #
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2009-2015 MongoDB Inc.
1
+ # Copyright (C) 2009-2016 MongoDB Inc.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -13,5 +13,5 @@
13
13
  # limitations under the License.
14
14
 
15
15
  module BSON
16
- VERSION = "4.1.1".freeze
16
+ VERSION = "4.2.0.rc0".freeze
17
17
  end
@@ -0,0 +1,1583 @@
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 BSON::Decimal128 do
18
+
19
+ let(:low_bits) do
20
+ decimal128.instance_variable_get(:@low)
21
+ end
22
+
23
+ let(:high_bits) do
24
+ decimal128.instance_variable_get(:@high)
25
+ end
26
+
27
+ describe '#initialize' do
28
+
29
+ context 'when the argument is neither a BigDecimal or String' do
30
+
31
+ it 'raises an ArgumentError' do
32
+ expect {
33
+ described_class.new(:invalid)
34
+ }.to raise_exception(ArgumentError)
35
+ end
36
+ end
37
+
38
+ shared_examples_for 'an initialized BSON::Decimal128' do
39
+
40
+ let(:decimal128) do
41
+ described_class.new(argument)
42
+ end
43
+
44
+ let(:buffer) do
45
+ decimal128.to_bson
46
+ end
47
+
48
+ let(:from_bson) do
49
+ described_class.from_bson(buffer)
50
+ end
51
+
52
+ it 'sets the correct high order bits' do
53
+ expect(high_bits).to eq(expected_high_bits)
54
+ end
55
+
56
+ it 'sets the correct low order bits' do
57
+ expect(low_bits).to eq(expected_low_bits)
58
+ end
59
+
60
+ it 'serializes to bson' do
61
+ expect(buffer.length).to eq(16)
62
+ end
63
+
64
+ it 'deserializes to the correct bits' do
65
+ expect(from_bson.instance_variable_get(:@high)).to eq(expected_high_bits)
66
+ expect(from_bson.instance_variable_get(:@low)).to eq(expected_low_bits)
67
+ end
68
+ end
69
+
70
+ context 'when the object represents positive infinity' do
71
+
72
+ let(:expected_high_bits) { 0x7800000000000000 }
73
+ let(:expected_low_bits) { 0x0000000000000000 }
74
+
75
+ context 'when a BigDecimal is passed' do
76
+
77
+ let(:argument) { BigDecimal.new("Infinity") }
78
+
79
+ it_behaves_like 'an initialized BSON::Decimal128'
80
+ end
81
+
82
+ context 'when a String is passed' do
83
+
84
+ let(:argument) { "Infinity" }
85
+
86
+ it_behaves_like 'an initialized BSON::Decimal128'
87
+ end
88
+ end
89
+
90
+ context 'when the object represents negative infinity' do
91
+
92
+ let(:expected_high_bits) { 0xf800000000000000 }
93
+ let(:expected_low_bits) { 0x0000000000000000 }
94
+
95
+ context 'when a BigDecimal is passed' do
96
+
97
+ let(:argument) { BigDecimal.new("-Infinity") }
98
+
99
+ it_behaves_like 'an initialized BSON::Decimal128'
100
+ end
101
+
102
+ context 'when a String is passed' do
103
+
104
+ let(:argument) { "-Infinity" }
105
+
106
+ it_behaves_like 'an initialized BSON::Decimal128'
107
+ end
108
+ end
109
+
110
+ context 'when the object represents NaN' do
111
+
112
+ let(:expected_high_bits) { 0x7c00000000000000 }
113
+ let(:expected_low_bits) { 0x0000000000000000 }
114
+
115
+ context 'when a BigDecimal is passed' do
116
+
117
+ let(:argument) { BigDecimal.new("NaN") }
118
+
119
+ it_behaves_like 'an initialized BSON::Decimal128'
120
+ end
121
+
122
+ context 'when a String is passed' do
123
+
124
+ let(:argument) { "NaN" }
125
+
126
+ it_behaves_like 'an initialized BSON::Decimal128'
127
+ end
128
+ end
129
+
130
+ context 'when the object represents -NaN' do
131
+
132
+ let(:expected_high_bits) { 0xfc00000000000000 }
133
+ let(:expected_low_bits) { 0x0000000000000000 }
134
+
135
+ context 'when a String is passed' do
136
+
137
+ let(:argument) { "-NaN" }
138
+
139
+ it_behaves_like 'an initialized BSON::Decimal128'
140
+ end
141
+ end
142
+
143
+ context 'when the object represents SNaN' do
144
+
145
+ let(:expected_high_bits) { 0x7e00000000000000 }
146
+ let(:expected_low_bits) { 0x0000000000000000 }
147
+
148
+ context 'when a String is passed' do
149
+
150
+ let(:argument) { "SNaN" }
151
+
152
+ it_behaves_like 'an initialized BSON::Decimal128'
153
+ end
154
+ end
155
+
156
+ context 'when the object represents -SNaN' do
157
+
158
+ let(:expected_high_bits) { 0xfe00000000000000 }
159
+ let(:expected_low_bits) { 0x0000000000000000 }
160
+
161
+ context 'when a String is passed' do
162
+
163
+ let(:argument) { "-SNaN" }
164
+
165
+ it_behaves_like 'an initialized BSON::Decimal128'
166
+ end
167
+ end
168
+
169
+ context 'when the object represents -0' do
170
+
171
+ let(:expected_high_bits) { 0xb040000000000000 }
172
+ let(:expected_low_bits) { 0x0000000000000000 }
173
+
174
+ context 'when a BigDecimal is passed' do
175
+
176
+ let(:argument) { BigDecimal.new("-0") }
177
+
178
+ it_behaves_like 'an initialized BSON::Decimal128'
179
+ end
180
+
181
+ context 'when a String is passed' do
182
+
183
+ let(:argument) { "-0" }
184
+
185
+ it_behaves_like 'an initialized BSON::Decimal128'
186
+ end
187
+ end
188
+
189
+ context 'when the object represents a positive integer' do
190
+
191
+ let(:expected_high_bits) { 0x3040000000000000 }
192
+ let(:expected_low_bits) { 0x000000000000000c }
193
+
194
+ context 'when a BigDecimal is passed' do
195
+
196
+ let(:argument) { BigDecimal.new(12) }
197
+
198
+ it_behaves_like 'an initialized BSON::Decimal128'
199
+ end
200
+
201
+ context 'when a String is passed' do
202
+
203
+ let(:argument) { "12" }
204
+
205
+ it_behaves_like 'an initialized BSON::Decimal128'
206
+ end
207
+ end
208
+
209
+ context 'when the object represents a negative integer' do
210
+
211
+ let(:expected_high_bits) { 0xb040000000000000 }
212
+ let(:expected_low_bits) { 0x000000000000000c }
213
+
214
+ context 'when a BigDecimal is passed' do
215
+
216
+ let(:argument) { BigDecimal.new(-12) }
217
+
218
+ it_behaves_like 'an initialized BSON::Decimal128'
219
+ end
220
+
221
+ context 'when a String is passed' do
222
+
223
+ let(:argument) { "-12" }
224
+
225
+ it_behaves_like 'an initialized BSON::Decimal128'
226
+ end
227
+ end
228
+
229
+ context 'when the object represents a positive float' do
230
+
231
+ let(:expected_high_bits) { 0x3036000000000000 }
232
+ let(:expected_low_bits) { 0x0000000000003039 }
233
+
234
+ context 'when a BigDecimal is passed' do
235
+
236
+ let(:argument) { BigDecimal.new(0.12345, 5) }
237
+
238
+ it_behaves_like 'an initialized BSON::Decimal128'
239
+ end
240
+
241
+ context 'when a String is passed' do
242
+
243
+ let(:argument) { "0.12345" }
244
+
245
+ it_behaves_like 'an initialized BSON::Decimal128'
246
+ end
247
+ end
248
+
249
+ context 'when the object represents a negative float' do
250
+
251
+ let(:expected_high_bits) { 0xb036000000000000 }
252
+ let(:expected_low_bits) { 0x0000000000003039 }
253
+
254
+ context 'when a BigDecimal is passed' do
255
+
256
+ let(:argument) { BigDecimal.new(-0.12345, 5) }
257
+
258
+ it_behaves_like 'an initialized BSON::Decimal128'
259
+ end
260
+
261
+ context 'when a String is passed' do
262
+
263
+ let(:argument) { "-0.12345" }
264
+
265
+ it_behaves_like 'an initialized BSON::Decimal128'
266
+ end
267
+ end
268
+
269
+ context 'when the object represents a large positive integer' do
270
+
271
+ let(:expected_high_bits) { 0x30403cde6fff9732 }
272
+ let(:expected_low_bits) { 0xde825cd07e96aff2 }
273
+
274
+ context 'when a BigDecimal is passed' do
275
+
276
+ let(:argument) { BigDecimal.new(1234567890123456789012345678901234) }
277
+
278
+ it_behaves_like 'an initialized BSON::Decimal128'
279
+ end
280
+
281
+ context 'when a String is passed' do
282
+
283
+ let(:argument) { "1234567890123456789012345678901234" }
284
+
285
+ it_behaves_like 'an initialized BSON::Decimal128'
286
+ end
287
+ end
288
+
289
+ context 'when the object represents a large negative integer' do
290
+
291
+ let(:expected_high_bits) { 0xb0403cde6fff9732 }
292
+ let(:expected_low_bits) { 0xde825cd07e96aff2 }
293
+
294
+ context 'when a BigDecimal is passed' do
295
+
296
+ let(:argument) { BigDecimal.new(-1234567890123456789012345678901234) }
297
+
298
+ it_behaves_like 'an initialized BSON::Decimal128'
299
+ end
300
+
301
+ context 'when a String is passed' do
302
+
303
+ let(:argument) { "-1234567890123456789012345678901234" }
304
+
305
+ it_behaves_like 'an initialized BSON::Decimal128'
306
+ end
307
+ end
308
+ end
309
+
310
+ context 'when deserializing' do
311
+
312
+ context 'When the value has trailing zeroes' do
313
+
314
+ let(:hex) do
315
+ '18000000136400D0070000000000000000000000003A3000'
316
+ end
317
+
318
+ let(:packed) do
319
+ [ hex ].pack('H*')
320
+ end
321
+
322
+ let(:buffer) do
323
+ BSON::ByteBuffer.new(packed)
324
+ end
325
+
326
+ let(:decimal128) do
327
+ BSON::Document.from_bson(buffer)['d']
328
+ end
329
+
330
+ let(:object_from_string) do
331
+ BSON::Decimal128.from_string('2.000')
332
+ end
333
+
334
+ it 'has the correct high order' do
335
+ expect(decimal128.instance_variable_get(:@high)).to eq(3475090062469758976)
336
+ end
337
+
338
+ it 'has the correct low order' do
339
+ expect(decimal128.instance_variable_get(:@low)).to eq(2000)
340
+ end
341
+
342
+ it 'matches the object created from a string' do
343
+ expect(object_from_string).to eq(decimal128)
344
+ end
345
+ end
346
+ end
347
+
348
+ describe '#from_string' do
349
+
350
+ shared_examples_for 'a decimal128 initialized from a string' do
351
+
352
+ let(:decimal128) do
353
+ BSON::Decimal128.from_string(string)
354
+ end
355
+
356
+ let(:low_bits) do
357
+ decimal128.instance_variable_get(:@low)
358
+ end
359
+
360
+ let(:high_bits) do
361
+ decimal128.instance_variable_get(:@high)
362
+ end
363
+
364
+ it 'sets the correct high order bits' do
365
+ expect(high_bits).to eq(expected_high_bits)
366
+ end
367
+
368
+ it 'sets the correct low order bits' do
369
+ expect(low_bits).to eq(expected_low_bits)
370
+ end
371
+ end
372
+
373
+ context 'when the string represents a special type' do
374
+
375
+ context "when the string is 'NaN'" do
376
+
377
+ let(:string) { 'NaN' }
378
+
379
+ let(:expected_high_bits) { 0x7c00000000000000 }
380
+ let(:expected_low_bits) { 0x0000000000000000 }
381
+
382
+ it_behaves_like 'a decimal128 initialized from a string'
383
+ end
384
+
385
+ context "when the string is '-NaN'" do
386
+
387
+ let(:string) { '-NaN' }
388
+
389
+ let(:expected_high_bits) { 0xfc00000000000000 }
390
+ let(:expected_low_bits) { 0x0000000000000000 }
391
+
392
+ it_behaves_like 'a decimal128 initialized from a string'
393
+ end
394
+
395
+ context "when the string is 'SNaN'" do
396
+
397
+ let(:string) { 'SNaN' }
398
+
399
+ let(:expected_high_bits) { 0x7e00000000000000 }
400
+ let(:expected_low_bits) { 0x0000000000000000 }
401
+
402
+ it_behaves_like 'a decimal128 initialized from a string'
403
+ end
404
+
405
+ context "when the string is '-SNaN'" do
406
+
407
+ let(:string) { '-SNaN' }
408
+
409
+ let(:expected_high_bits) { 0xfe00000000000000 }
410
+ let(:expected_low_bits) { 0x0000000000000000 }
411
+
412
+ it_behaves_like 'a decimal128 initialized from a string'
413
+ end
414
+
415
+ context "when the string is 'Infinity'" do
416
+
417
+ let(:string) { 'Infinity' }
418
+
419
+ let(:expected_exponent) { nil }
420
+ let(:expected_significand) { nil }
421
+ let(:expected_high_bits) { 0x7800000000000000 }
422
+ let(:expected_low_bits) { 0x0000000000000000 }
423
+
424
+ it_behaves_like 'a decimal128 initialized from a string'
425
+ end
426
+
427
+ context "when the string is '-Infinity'" do
428
+
429
+ let(:string) { '-Infinity' }
430
+
431
+ let(:expected_exponent) { nil }
432
+ let(:expected_significand) { nil }
433
+ let(:expected_high_bits) { 0xf800000000000000 }
434
+ let(:expected_low_bits) { 0x0000000000000000 }
435
+
436
+ it_behaves_like 'a decimal128 initialized from a string'
437
+ end
438
+ end
439
+
440
+ context 'when the string represents 0' do
441
+
442
+ context "when the string is '0'" do
443
+
444
+ let(:string) { '0' }
445
+
446
+ let(:expected_exponent) { 0 }
447
+ let(:expected_significand) { 0 }
448
+ let(:expected_high_bits) { 0x3040000000000000 }
449
+ let(:expected_low_bits) { 0 }
450
+
451
+ it_behaves_like 'a decimal128 initialized from a string'
452
+ end
453
+
454
+ context "when the string is '-0'" do
455
+
456
+ let(:string) { '-0' }
457
+
458
+ let(:expected_exponent) { 0 }
459
+ let(:expected_significand) { 0 }
460
+ let(:expected_high_bits) { 0xb040000000000000 }
461
+ let(:expected_low_bits) { 0 }
462
+
463
+ it_behaves_like 'a decimal128 initialized from a string'
464
+ end
465
+
466
+ context "when the string is '0.0'" do
467
+
468
+ let(:string) { '0.0' }
469
+
470
+ let(:expected_exponent) { -1 }
471
+ let(:expected_significand) { 0 }
472
+ let(:expected_high_bits) { 0x303e000000000000 }
473
+ let(:expected_low_bits) { 0 }
474
+
475
+ it_behaves_like 'a decimal128 initialized from a string'
476
+ end
477
+ end
478
+
479
+ context 'when the string represents an integer' do
480
+
481
+ context "when the string is '1'" do
482
+
483
+ let(:string) { '1' }
484
+
485
+ let(:expected_exponent) { 0 }
486
+ let(:expected_significand) { 1 }
487
+ let(:expected_high_bits) { 0x3040000000000000 }
488
+ let(:expected_low_bits) { 0x1 }
489
+
490
+ it_behaves_like 'a decimal128 initialized from a string'
491
+ end
492
+
493
+ context "when the string is '-1'" do
494
+
495
+ let(:string) { '-1'}
496
+
497
+ let(:expected_exponent) { 0 }
498
+ let(:expected_significand) { 1 }
499
+ let(:expected_high_bits) { 0xb040000000000000 }
500
+ let(:expected_low_bits) { 0x1 }
501
+
502
+ it_behaves_like 'a decimal128 initialized from a string'
503
+ end
504
+
505
+ context "when the string is '20'" do
506
+
507
+ let(:string) { '20' }
508
+
509
+ let(:expected_exponent) { 0 }
510
+ let(:expected_significand) { 20 }
511
+ let(:expected_low_bits) { 0x14 }
512
+ let(:expected_high_bits) { 0x3040000000000000 }
513
+
514
+ it_behaves_like 'a decimal128 initialized from a string'
515
+ end
516
+
517
+ context "when the string is '-20'" do
518
+
519
+ let(:string) { '-20' }
520
+
521
+ let(:expected_exponent) { 0 }
522
+ let(:expected_significand) { 20 }
523
+ let(:expected_low_bits) { 0x14 }
524
+ let(:expected_high_bits) { 0xb040000000000000 }
525
+
526
+ it_behaves_like 'a decimal128 initialized from a string'
527
+ end
528
+
529
+ context "when the string is '12345678901234567'" do
530
+
531
+ let(:string) { '12345678901234567' }
532
+
533
+ let(:expected_exponent) { 0 }
534
+ let(:expected_significand) { 12345678901234567 }
535
+ let(:expected_low_bits) { 0x002bdc545d6b4b87 }
536
+ let(:expected_high_bits) { 0x3040000000000000 }
537
+
538
+ it_behaves_like 'a decimal128 initialized from a string'
539
+ end
540
+
541
+ context "when the string is '-12345678901234567'" do
542
+
543
+ let(:string) { '-12345678901234567' }
544
+
545
+ let(:expected_exponent) { 0 }
546
+ let(:expected_significand) { 12345678901234567 }
547
+ let(:expected_low_bits) { 0x002bdc545d6b4b87 }
548
+ let(:expected_high_bits) { 0xb040000000000000 }
549
+
550
+ it_behaves_like 'a decimal128 initialized from a string'
551
+ end
552
+
553
+ context "when the string is '12345689012345789012345'" do
554
+
555
+ let(:string) { '12345689012345789012345' }
556
+
557
+ let(:expected_exponent) { 0 }
558
+ let(:expected_significand) { 12345689012345789012345 }
559
+ let(:expected_low_bits) { 0x42da3a76f9e0d979 }
560
+ let(:expected_high_bits) { 0x304000000000029d }
561
+
562
+ it_behaves_like 'a decimal128 initialized from a string'
563
+ end
564
+
565
+ context "when the string is '-12345689012345789012345'" do
566
+
567
+ let(:string) { '-12345689012345789012345' }
568
+
569
+ let(:expected_exponent) { 0 }
570
+ let(:expected_significand) { 12345689012345789012345 }
571
+ let(:expected_low_bits) { 0x42da3a76f9e0d979 }
572
+ let(:expected_high_bits) { 0xb04000000000029d }
573
+
574
+ it_behaves_like 'a decimal128 initialized from a string'
575
+ end
576
+ end
577
+
578
+ context 'when the string represents a fraction' do
579
+
580
+ context "when the string is '0.1'" do
581
+
582
+ let(:string) { '0.1' }
583
+
584
+ let(:expected_exponent) { -1 }
585
+ let(:expected_significand) { 1 }
586
+ let(:expected_low_bits) { 0x1 }
587
+ let(:expected_high_bits) { 0x303e000000000000 }
588
+
589
+ it_behaves_like 'a decimal128 initialized from a string'
590
+ end
591
+
592
+ context "when the string is '-0.1'" do
593
+
594
+ let(:string) { '-0.1' }
595
+
596
+ let(:expected_exponent) { -1 }
597
+ let(:expected_significand) { 1 }
598
+ let(:expected_low_bits) { 0x1 }
599
+ let(:expected_high_bits) { 0xb03e000000000000 }
600
+
601
+ it_behaves_like 'a decimal128 initialized from a string'
602
+ end
603
+
604
+ context "when the string is '0.123'" do
605
+
606
+ let(:string) { '0.123' }
607
+
608
+ let(:expected_exponent) { -3 }
609
+ let(:expected_significand) { 123 }
610
+ let(:expected_low_bits) { 0x7b }
611
+ let(:expected_high_bits) { 0x303a000000000000 }
612
+
613
+ it_behaves_like 'a decimal128 initialized from a string'
614
+ end
615
+
616
+ context "when the string is '-0.123'" do
617
+
618
+ let(:string) { '-0.123' }
619
+
620
+ let(:expected_exponent) { -3 }
621
+ let(:expected_significand) { 123 }
622
+ let(:expected_low_bits) { 0x7b }
623
+ let(:expected_high_bits) { 0xb03a000000000000 }
624
+
625
+ it_behaves_like 'a decimal128 initialized from a string'
626
+ end
627
+
628
+ context "when the string is '0.1234567890123456789012345678901234'" do
629
+
630
+ let(:string) { '0.1234567890123456789012345678901234' }
631
+
632
+ let(:expected_exponent) { -34 }
633
+ let(:expected_significand) { 1234567890123456789012345678901234 }
634
+ let(:expected_low_bits) { 0xde825cd07e96aff2 }
635
+ let(:expected_high_bits) { 0x2ffc3cde6fff9732 }
636
+
637
+ it_behaves_like 'a decimal128 initialized from a string'
638
+ end
639
+ end
640
+
641
+ context 'when the string represents a fraction with a whole number' do
642
+
643
+ context "when the string is '1.2'" do
644
+
645
+ let(:string) { '1.2' }
646
+
647
+ let(:expected_exponent) { -1 }
648
+ let(:expected_significand) { 12 }
649
+ let(:expected_low_bits) { 0xc }
650
+ let(:expected_high_bits) { 0x303e000000000000 }
651
+
652
+ it_behaves_like 'a decimal128 initialized from a string'
653
+ end
654
+
655
+ context "when the string is '-1.2'" do
656
+
657
+ let(:string) { '-1.2' }
658
+
659
+ let(:expected_exponent) { -1 }
660
+ let(:expected_significand) { 12 }
661
+ let(:expected_low_bits) { 0xc }
662
+ let(:expected_high_bits) { 0xb03e000000000000 }
663
+
664
+ it_behaves_like 'a decimal128 initialized from a string'
665
+ end
666
+
667
+ context "when the string is '1.234'" do
668
+
669
+ let(:string) { '1.234' }
670
+
671
+ let(:expected_exponent) { -3 }
672
+ let(:expected_significand) { 1234 }
673
+ let(:expected_low_bits) { 0x4d2 }
674
+ let(:expected_high_bits) { 0x303a000000000000 }
675
+
676
+ it_behaves_like 'a decimal128 initialized from a string'
677
+ end
678
+
679
+ context "when the string is '-1.234'" do
680
+
681
+ let(:string) { '-1.234' }
682
+
683
+ let(:expected_exponent) { -3 }
684
+ let(:expected_significand) { 1234 }
685
+ let(:expected_low_bits) { 0x4d2 }
686
+ let(:expected_high_bits) { 0xb03a000000000000 }
687
+
688
+ it_behaves_like 'a decimal128 initialized from a string'
689
+ end
690
+
691
+ context "when the string is '123456789.123456789'" do
692
+
693
+ let(:string) { '123456789.123456789' }
694
+
695
+ let(:expected_exponent) { -9 }
696
+ let(:expected_significand) { 123456789123456789 }
697
+ let(:expected_low_bits) { 0x1b69b4bacd05f15 }
698
+ let(:expected_high_bits) { 0x302e000000000000 }
699
+
700
+ it_behaves_like 'a decimal128 initialized from a string'
701
+ end
702
+
703
+ context "when the string is '-123456789.123456789'" do
704
+
705
+ let(:string) { '-123456789.123456789' }
706
+
707
+ let(:expected_exponent) { -9 }
708
+ let(:expected_significand) { 123456789123456789 }
709
+ let(:expected_low_bits) { 0x1b69b4bacd05f15 }
710
+ let(:expected_high_bits) { 0xb02e000000000000 }
711
+
712
+ it_behaves_like 'a decimal128 initialized from a string'
713
+ end
714
+ end
715
+
716
+ context 'when the string represents a decimal with trailing zeros' do
717
+
718
+ context "when the string is '1.000'" do
719
+
720
+ let(:string) { '1.000' }
721
+
722
+ let(:expected_exponent) { -3 }
723
+ let(:expected_significand) { 1000 }
724
+ let(:expected_low_bits) { 0x3e8 }
725
+ let(:expected_high_bits) { 0x303a000000000000 }
726
+
727
+ it_behaves_like 'a decimal128 initialized from a string'
728
+ end
729
+
730
+ context "when the string is '-1.000'" do
731
+
732
+ let(:string) { '-1.000' }
733
+
734
+ let(:expected_exponent) { -3 }
735
+ let(:expected_significand) { 1000 }
736
+ let(:expected_low_bits) { 0x3e8 }
737
+ let(:expected_high_bits) { 0xb03a000000000000 }
738
+
739
+ it_behaves_like 'a decimal128 initialized from a string'
740
+ end
741
+
742
+ context "when the string is '100.000'" do
743
+
744
+ let(:string) { '100.000' }
745
+
746
+ let(:expected_exponent) { -3 }
747
+ let(:expected_significand) { 100000 }
748
+ let(:expected_low_bits) { 0x186a0 }
749
+ let(:expected_high_bits) { 0x303a000000000000 }
750
+
751
+ it_behaves_like 'a decimal128 initialized from a string'
752
+ end
753
+
754
+ context "when the string is '-100.000'" do
755
+
756
+ let(:string) { '-100.000' }
757
+
758
+ let(:expected_exponent) { -3 }
759
+ let(:expected_significand) { 100000 }
760
+ let(:expected_low_bits) { 0x186a0 }
761
+ let(:expected_high_bits) { 0xb03a000000000000 }
762
+
763
+ it_behaves_like 'a decimal128 initialized from a string'
764
+ end
765
+
766
+ context "when the string is '1.234000000'" do
767
+
768
+ let(:string) { '1.234000000' }
769
+
770
+ let(:expected_exponent) { -9 }
771
+ let(:expected_significand) { 1234000000 }
772
+ let(:expected_low_bits) { 0x498d5880 }
773
+ let(:expected_high_bits) { 0x302e000000000000 }
774
+
775
+ it_behaves_like 'a decimal128 initialized from a string'
776
+ end
777
+
778
+ context "when the string is '-1.234000000'" do
779
+
780
+ let(:string) { '-1.234000000' }
781
+
782
+ let(:expected_exponent) { -9 }
783
+ let(:expected_significand) { 1234000000 }
784
+ let(:expected_low_bits) { 0x498d5880 }
785
+ let(:expected_high_bits) { 0xb02e000000000000 }
786
+
787
+ it_behaves_like 'a decimal128 initialized from a string'
788
+ end
789
+
790
+ context 'when there are zeros following the decimal that are not trailing' do
791
+
792
+ context "when the string is '0.001234'" do
793
+
794
+ let(:string) { '0.001234' }
795
+
796
+ let(:expected_exponent) { -6 }
797
+ let(:expected_significand) { 1234 }
798
+ let(:expected_low_bits) { 0x4d2 }
799
+ let(:expected_high_bits) { 0x3034000000000000 }
800
+
801
+ it_behaves_like 'a decimal128 initialized from a string'
802
+ end
803
+ end
804
+
805
+ context 'when there are zeros following the decimal that are not trailing' do
806
+
807
+ context "when the string is '0.00123400000'" do
808
+
809
+ let(:string) { '0.00123400000' }
810
+
811
+ let(:expected_exponent) { -11 }
812
+ let(:expected_significand) { 123400000 }
813
+ let(:expected_low_bits) { 0x75aef40 }
814
+ let(:expected_high_bits) { 0x302a000000000000 }
815
+
816
+ it_behaves_like 'a decimal128 initialized from a string'
817
+ end
818
+ end
819
+ end
820
+
821
+ context 'when the string uses scientific notation' do
822
+
823
+ context 'when the exponent is positive' do
824
+
825
+ context 'when the positive exponent is denoted with E' do
826
+
827
+ context "when the string is '1.2E4'" do
828
+
829
+ let(:string) { '1.2E4' }
830
+
831
+ let(:expected_exponent) { 3 }
832
+ let(:expected_significand) { 12 }
833
+ let(:expected_low_bits) { 0xc }
834
+ let(:expected_high_bits) { 0x3046000000000000 }
835
+
836
+ it_behaves_like 'a decimal128 initialized from a string'
837
+ end
838
+
839
+ context "when the string is '-1.2E4'" do
840
+
841
+ let(:string) { '-1.2E4' }
842
+
843
+ let(:expected_exponent) { 3 }
844
+ let(:expected_significand) { 12 }
845
+ let(:expected_low_bits) { 0xc }
846
+ let(:expected_high_bits) { 0xb046000000000000 }
847
+
848
+ it_behaves_like 'a decimal128 initialized from a string'
849
+ end
850
+ end
851
+
852
+ context 'when the positive exponent is denoted with E+' do
853
+
854
+ context "when the string is '1.2E+4'" do
855
+
856
+ let(:string) { '1.2E4' }
857
+
858
+ let(:expected_exponent) { 3 }
859
+ let(:expected_significand) { 12 }
860
+ let(:expected_low_bits) { 0xc }
861
+ let(:expected_high_bits) { 0x3046000000000000 }
862
+
863
+ it_behaves_like 'a decimal128 initialized from a string'
864
+ end
865
+
866
+ context "when the string is '-1.2E+4'" do
867
+
868
+ let(:string) { '-1.2E4' }
869
+
870
+ let(:expected_exponent) { 3 }
871
+ let(:expected_significand) { 12 }
872
+ let(:expected_low_bits) { 0xc }
873
+ let(:expected_high_bits) { 0xb046000000000000 }
874
+
875
+ it_behaves_like 'a decimal128 initialized from a string'
876
+ end
877
+ end
878
+ end
879
+
880
+ context 'when the exponent is negative' do
881
+
882
+ context "when the string is '1.2E-4'" do
883
+
884
+ let(:string) { '1.2E-4' }
885
+
886
+ let(:expected_exponent) { -5 }
887
+ let(:expected_significand) { 12 }
888
+ let(:expected_low_bits) { 0xc }
889
+ let(:expected_high_bits) { 0x3036000000000000 }
890
+
891
+ it_behaves_like 'a decimal128 initialized from a string'
892
+ end
893
+
894
+ context "when the string is '-1.2E-4'" do
895
+
896
+ let(:string) { '-1.2E-4' }
897
+
898
+ let(:expected_exponent) { -5 }
899
+ let(:expected_significand) { 12 }
900
+ let(:expected_low_bits) { 0xc }
901
+ let(:expected_high_bits) { 0xb036000000000000 }
902
+
903
+ it_behaves_like 'a decimal128 initialized from a string'
904
+ end
905
+
906
+ context 'when there are trailing zeros' do
907
+
908
+ context "when the string is '1.200E-4'" do
909
+
910
+ let(:string) { '1.200E-4' }
911
+
912
+ let(:expected_exponent) { -7 }
913
+ let(:expected_significand) { 1200 }
914
+ let(:expected_low_bits) { 0x4b0 }
915
+ let(:expected_high_bits) { 0x3032000000000000 }
916
+
917
+ it_behaves_like 'a decimal128 initialized from a string'
918
+ end
919
+
920
+ context "when the string is '-1.200E-4'" do
921
+
922
+ let(:string) { '-1.200E-4' }
923
+
924
+ let(:expected_exponent) { -7 }
925
+ let(:expected_significand) { 1200 }
926
+ let(:expected_low_bits) { 0x4b0 }
927
+ let(:expected_high_bits) { 0xb032000000000000 }
928
+
929
+ it_behaves_like 'a decimal128 initialized from a string'
930
+ end
931
+ end
932
+ end
933
+ end
934
+ end
935
+
936
+ describe '#to_s' do
937
+
938
+ shared_examples_for 'a decimal128 printed to a string' do
939
+
940
+ let(:buffer) do
941
+ buffer = BSON::ByteBuffer.new
942
+ buffer.put_decimal128(low_bits, high_bits)
943
+ end
944
+ let(:decimal) { BSON::Decimal128.from_bson(buffer) }
945
+
946
+ it 'prints the correct string' do
947
+ expect(decimal.to_s).to eq(expected_string)
948
+ end
949
+ end
950
+
951
+ context 'when the bits represent a special type' do
952
+
953
+ context 'when the decimal is NaN' do
954
+
955
+ let(:expected_string) { 'NaN' }
956
+ let(:high_bits) { 0x7c00000000000000 }
957
+ let(:low_bits) { 0x0 }
958
+
959
+ it_behaves_like 'a decimal128 printed to a string'
960
+ end
961
+
962
+ context 'when the decimal is negative NaN' do
963
+
964
+ let(:expected_string) { 'NaN' }
965
+ let(:high_bits) { 0xfc00000000000000 }
966
+ let(:low_bits) { 0x0000000000000000 }
967
+
968
+ it_behaves_like 'a decimal128 printed to a string'
969
+ end
970
+
971
+ context 'when the decimal is SNaN' do
972
+
973
+ let(:expected_string) { 'NaN' }
974
+ let(:high_bits) { 0x7e00000000000000 }
975
+ let(:low_bits) { 0x0000000000000000 }
976
+
977
+ it_behaves_like 'a decimal128 printed to a string'
978
+ end
979
+
980
+ context 'when the decimal is -SNaN' do
981
+
982
+ let(:expected_string) { 'NaN' }
983
+ let(:high_bits) { 0xfe00000000000000 }
984
+ let(:low_bits) { 0x0000000000000000 }
985
+
986
+ it_behaves_like 'a decimal128 printed to a string'
987
+ end
988
+
989
+ context 'when the decimal is NaN with a payload' do
990
+
991
+ let(:expected_string) { 'NaN' }
992
+ let(:high_bits) { 0x7e00000000000000 }
993
+ let(:low_bits) { 0x0000000000000008 }
994
+
995
+ it_behaves_like 'a decimal128 printed to a string'
996
+ end
997
+
998
+ context 'when the decimal is positive Infinity' do
999
+
1000
+ let(:expected_string) { 'Infinity' }
1001
+ let(:high_bits) { 0x7800000000000000 }
1002
+ let(:low_bits) { 0x0000000000000000 }
1003
+
1004
+ it_behaves_like 'a decimal128 printed to a string'
1005
+ end
1006
+
1007
+ context 'when the decimal is negative Infinity' do
1008
+
1009
+ let(:expected_string) { '-Infinity' }
1010
+ let(:high_bits) { 0xf800000000000000 }
1011
+ let(:low_bits) { 0x0000000000000000 }
1012
+
1013
+ it_behaves_like 'a decimal128 printed to a string'
1014
+ end
1015
+ end
1016
+
1017
+ context 'when the string represents an integer' do
1018
+
1019
+ context 'when the decimal is 1' do
1020
+
1021
+ let(:expected_string) { '1' }
1022
+ let(:high_bits) { 0x3040000000000000 }
1023
+ let(:low_bits) { 0x0000000000000001 }
1024
+
1025
+ it_behaves_like 'a decimal128 printed to a string'
1026
+ end
1027
+
1028
+ context 'when the decimal is -1' do
1029
+
1030
+ let(:expected_string) { '-1' }
1031
+ let(:high_bits) { 0xb040000000000000 }
1032
+ let(:low_bits) { 0x0000000000000001 }
1033
+
1034
+ it_behaves_like 'a decimal128 printed to a string'
1035
+ end
1036
+
1037
+ context 'when the decimal is 20' do
1038
+
1039
+ let(:expected_string) { '20' }
1040
+ let(:high_bits) { 0x3040000000000000 }
1041
+ let(:low_bits) { 0x0000000000000014 }
1042
+
1043
+ it_behaves_like 'a decimal128 printed to a string'
1044
+ end
1045
+
1046
+ context 'when the decimal is -20' do
1047
+
1048
+ let(:expected_string) { '-20' }
1049
+ let(:high_bits) { 0xb040000000000000 }
1050
+ let(:low_bits) { 0x0000000000000014 }
1051
+
1052
+ it_behaves_like 'a decimal128 printed to a string'
1053
+ end
1054
+
1055
+ context 'when the decimal is 12345678901234567' do
1056
+
1057
+ let(:expected_string) { '12345678901234567' }
1058
+ let(:high_bits) { 0x3040000000000000 }
1059
+ let(:low_bits) { 0x002bdc545d6b4b87 }
1060
+
1061
+ it_behaves_like 'a decimal128 printed to a string'
1062
+ end
1063
+
1064
+ context 'when the decimal is -12345678901234567' do
1065
+
1066
+ let(:expected_string) { '-12345678901234567' }
1067
+ let(:high_bits) { 0xb040000000000000 }
1068
+ let(:low_bits) { 0x002bdc545d6b4b87 }
1069
+
1070
+ it_behaves_like 'a decimal128 printed to a string'
1071
+ end
1072
+
1073
+ context 'when the decimal is 12345689012345789012345' do
1074
+
1075
+ let(:expected_string) { '12345689012345789012345' }
1076
+ let(:high_bits) { 0x304000000000029d }
1077
+ let(:low_bits) { 0x42da3a76f9e0d979 }
1078
+
1079
+ it_behaves_like 'a decimal128 printed to a string'
1080
+ end
1081
+
1082
+ context 'when the decimal is -12345689012345789012345' do
1083
+
1084
+ let(:expected_string) { '-12345689012345789012345' }
1085
+ let(:high_bits) { 0xb04000000000029d }
1086
+ let(:low_bits) { 0x42da3a76f9e0d979 }
1087
+
1088
+ it_behaves_like 'a decimal128 printed to a string'
1089
+ end
1090
+ end
1091
+
1092
+ context 'when the string represents a fraction' do
1093
+
1094
+ context 'when the decimal is 0.1' do
1095
+
1096
+ let(:expected_string) { '0.1' }
1097
+ let(:high_bits) { 0x303e000000000000 }
1098
+ let(:low_bits) { 0x0000000000000001 }
1099
+
1100
+ it_behaves_like 'a decimal128 printed to a string'
1101
+ end
1102
+
1103
+ context 'when the decimal is -0.1' do
1104
+
1105
+ let(:expected_string) { '-0.1' }
1106
+ let(:high_bits) { 0xb03e000000000000 }
1107
+ let(:low_bits) { 0x0000000000000001 }
1108
+
1109
+ it_behaves_like 'a decimal128 printed to a string'
1110
+ end
1111
+
1112
+ context 'when the decimal is 0.123' do
1113
+
1114
+ let(:expected_string) { '0.123' }
1115
+ let(:high_bits) { 0x303a000000000000 }
1116
+ let(:low_bits) { 0x000000000000007b }
1117
+
1118
+ it_behaves_like 'a decimal128 printed to a string'
1119
+ end
1120
+
1121
+ context 'when the decimal is -0.123' do
1122
+
1123
+ let(:expected_string) { '-0.123' }
1124
+ let(:high_bits) { 0xb03a000000000000 }
1125
+ let(:low_bits) { 0x000000000000007b }
1126
+
1127
+ it_behaves_like 'a decimal128 printed to a string'
1128
+ end
1129
+ end
1130
+
1131
+ context 'when the decimal should have leading zeros' do
1132
+
1133
+ let(:expected_string) { '0.001234' }
1134
+ let(:high_bits) { 0x3034000000000000 }
1135
+ let(:low_bits) { 0x00000000000004d2 }
1136
+
1137
+ it_behaves_like 'a decimal128 printed to a string'
1138
+ end
1139
+
1140
+ context 'when the decimal has trailing zeros' do
1141
+
1142
+ let(:expected_string) { '2.000' }
1143
+ let(:high_bits) { 0x303a000000000000 }
1144
+ let(:low_bits) { 0x00000000000007d0 }
1145
+
1146
+ it_behaves_like 'a decimal128 printed to a string'
1147
+ end
1148
+ end
1149
+
1150
+ describe "#==" do
1151
+
1152
+ context "when the high and low bits are identical" do
1153
+
1154
+ let(:string) do
1155
+ '1.23'
1156
+ end
1157
+
1158
+ let(:decimal128) do
1159
+ described_class.from_string(string)
1160
+ end
1161
+
1162
+ let(:other_decimal) do
1163
+ described_class.from_string(string)
1164
+ end
1165
+
1166
+ it "returns true" do
1167
+ expect(decimal128).to eq(other_decimal)
1168
+ end
1169
+ end
1170
+
1171
+ context "when the high and low bits are different" do
1172
+
1173
+ let(:string) do
1174
+ '1.23'
1175
+ end
1176
+
1177
+ let(:decimal128) do
1178
+ described_class.from_string(string)
1179
+ end
1180
+
1181
+ it "returns false" do
1182
+ expect(decimal128).to_not eq(described_class.new(BigDecimal.new('2.00')))
1183
+ end
1184
+ end
1185
+
1186
+ context "when other is not a decimal128" do
1187
+
1188
+ it "returns false" do
1189
+ expect(described_class.from_string('1')).to_not eq(nil)
1190
+ end
1191
+ end
1192
+ end
1193
+
1194
+ describe "#===" do
1195
+
1196
+ let(:decimal128) do
1197
+ described_class.new(BigDecimal.new('1.23'))
1198
+ end
1199
+
1200
+ context "when comparing with another decimal128" do
1201
+
1202
+ context "when the high and low bits are equal" do
1203
+
1204
+ let(:other) do
1205
+ described_class.from_string(decimal128.to_s)
1206
+ end
1207
+
1208
+ it "returns true" do
1209
+ expect(decimal128 === other).to be true
1210
+ end
1211
+ end
1212
+
1213
+ context "when the high and low bits are not equal" do
1214
+
1215
+ let(:other) do
1216
+ described_class.new(BigDecimal.new('1000.003'))
1217
+ end
1218
+
1219
+ it "returns false" do
1220
+ expect(decimal128 === other).to be false
1221
+ end
1222
+ end
1223
+ end
1224
+
1225
+ context "when comparing to an decimal128 class" do
1226
+
1227
+ it "returns false" do
1228
+ expect(decimal128 === BSON::Decimal128).to be false
1229
+ end
1230
+ end
1231
+
1232
+ context "when comparing with a non string or decimal128" do
1233
+
1234
+ it "returns false" do
1235
+ expect(decimal128 === "test").to be false
1236
+ end
1237
+ end
1238
+
1239
+ context "when comparing with a non decimal128 class" do
1240
+
1241
+ it "returns false" do
1242
+ expect(decimal128 === String).to be false
1243
+ end
1244
+ end
1245
+ end
1246
+
1247
+ describe "#as_json" do
1248
+
1249
+ let(:object) do
1250
+ described_class.new(BigDecimal.new('1.23'))
1251
+ end
1252
+
1253
+ it "returns the decimal128 with $numberDecimal key" do
1254
+ expect(object.as_json).to eq({ "$numberDecimal" => object.to_s })
1255
+ end
1256
+ end
1257
+
1258
+ describe "::BSON_TYPE" do
1259
+
1260
+ it "returns 0x13" do
1261
+ expect(described_class::BSON_TYPE).to eq(19.chr)
1262
+ end
1263
+ end
1264
+
1265
+ describe "#bson_type" do
1266
+
1267
+ let(:code) do
1268
+ described_class.new(BigDecimal.new('1.23'))
1269
+ end
1270
+
1271
+ it "returns 0x13" do
1272
+ expect(code.bson_type).to eq(described_class::BSON_TYPE)
1273
+ end
1274
+ end
1275
+
1276
+ describe "#eql" do
1277
+
1278
+ context "when high and low bits are identical" do
1279
+
1280
+ let(:string) do
1281
+ '2.00'
1282
+ end
1283
+
1284
+ let(:decimal128) do
1285
+ described_class.from_string(string)
1286
+ end
1287
+
1288
+ let(:other_decimal) do
1289
+ described_class.from_string(string)
1290
+ end
1291
+
1292
+ it "returns true" do
1293
+ expect(decimal128).to eql(other_decimal)
1294
+ end
1295
+ end
1296
+
1297
+ context "when the high and low bit are different" do
1298
+
1299
+ let(:string) do
1300
+ '2.00'
1301
+ end
1302
+
1303
+ let(:decimal128) do
1304
+ described_class.from_string(string)
1305
+ end
1306
+
1307
+ it "returns false" do
1308
+ expect(decimal128).to_not eql(described_class.new(BigDecimal.new('2')))
1309
+ end
1310
+ end
1311
+
1312
+ context "when other is not a Decimal128" do
1313
+
1314
+ it "returns false" do
1315
+ expect(described_class.from_string('2')).to_not eql(nil)
1316
+ end
1317
+ end
1318
+ end
1319
+
1320
+ describe "#hash" do
1321
+
1322
+ let(:decimal128) do
1323
+ described_class.new(BigDecimal.new('-1234E+33'))
1324
+ end
1325
+
1326
+ it "returns a hash of the high and low bits" do
1327
+ expect(decimal128.hash).to eq(BSON::Decimal128.from_bson(decimal128.to_bson).hash)
1328
+ end
1329
+ end
1330
+
1331
+ describe "#inspect" do
1332
+
1333
+ let(:decimal128) do
1334
+ described_class.new(BigDecimal.new('1.23'))
1335
+ end
1336
+
1337
+ it "returns the inspection with the decimal128 to_s" do
1338
+ expect(decimal128.inspect).to eq("BSON::Decimal128('#{decimal128.to_s}')")
1339
+ end
1340
+ end
1341
+
1342
+ describe "#to_big_decimal" do
1343
+
1344
+ shared_examples_for 'a decimal128 convertible to a Ruby BigDecimal' do
1345
+
1346
+ let(:decimal128) do
1347
+ described_class.new(big_decimal)
1348
+ end
1349
+
1350
+ it 'properly converts the Decimal128 to a BigDecimal' do
1351
+ expect(decimal128.to_big_decimal).to eq(expected_big_decimal)
1352
+ end
1353
+ end
1354
+
1355
+ context 'when the Decimal128 is a special type' do
1356
+
1357
+ context 'when the value is Infinity' do
1358
+
1359
+ let(:big_decimal) do
1360
+ BigDecimal.new('Infinity')
1361
+ end
1362
+
1363
+ let(:expected_big_decimal) do
1364
+ big_decimal
1365
+ end
1366
+
1367
+ it_behaves_like 'a decimal128 convertible to a Ruby BigDecimal'
1368
+ end
1369
+
1370
+ context 'when the value is -Infinity' do
1371
+
1372
+ let(:big_decimal) do
1373
+ BigDecimal.new('-Infinity')
1374
+ end
1375
+
1376
+ let(:expected_big_decimal) do
1377
+ big_decimal
1378
+ end
1379
+
1380
+ it_behaves_like 'a decimal128 convertible to a Ruby BigDecimal'
1381
+ end
1382
+ end
1383
+
1384
+ context 'when the value represents an Integer' do
1385
+
1386
+ context 'when the value is 1' do
1387
+
1388
+ let(:big_decimal) do
1389
+ BigDecimal.new(1)
1390
+ end
1391
+
1392
+ let(:expected_big_decimal) do
1393
+ big_decimal
1394
+ end
1395
+
1396
+ it_behaves_like 'a decimal128 convertible to a Ruby BigDecimal'
1397
+ end
1398
+
1399
+ context 'when the value is -1' do
1400
+
1401
+ let(:big_decimal) do
1402
+ BigDecimal.new(-1)
1403
+ end
1404
+
1405
+ let(:expected_big_decimal) do
1406
+ big_decimal
1407
+ end
1408
+
1409
+ it_behaves_like 'a decimal128 convertible to a Ruby BigDecimal'
1410
+ end
1411
+
1412
+ context 'when the value is 20' do
1413
+
1414
+ let(:big_decimal) do
1415
+ BigDecimal.new(20)
1416
+ end
1417
+
1418
+ let(:expected_big_decimal) do
1419
+ big_decimal
1420
+ end
1421
+
1422
+ it_behaves_like 'a decimal128 convertible to a Ruby BigDecimal'
1423
+ end
1424
+
1425
+ context 'when the value is -20' do
1426
+
1427
+ let(:big_decimal) do
1428
+ BigDecimal.new(-20)
1429
+ end
1430
+
1431
+ let(:expected_big_decimal) do
1432
+ big_decimal
1433
+ end
1434
+
1435
+ it_behaves_like 'a decimal128 convertible to a Ruby BigDecimal'
1436
+ end
1437
+
1438
+ context 'when the value is 12345678901234567' do
1439
+
1440
+ let(:big_decimal) do
1441
+ BigDecimal.new(12345678901234567)
1442
+ end
1443
+
1444
+ let(:expected_big_decimal) do
1445
+ big_decimal
1446
+ end
1447
+
1448
+ it_behaves_like 'a decimal128 convertible to a Ruby BigDecimal'
1449
+ end
1450
+
1451
+ context 'when the value is -12345678901234567' do
1452
+
1453
+ let(:big_decimal) do
1454
+ BigDecimal.new(-12345678901234567)
1455
+ end
1456
+
1457
+ let(:expected_big_decimal) do
1458
+ big_decimal
1459
+ end
1460
+
1461
+ it_behaves_like 'a decimal128 convertible to a Ruby BigDecimal'
1462
+ end
1463
+
1464
+ context 'when the value is 12345689012345789012345' do
1465
+
1466
+ let(:big_decimal) do
1467
+ BigDecimal.new(12345689012345789012345)
1468
+ end
1469
+
1470
+ let(:expected_big_decimal) do
1471
+ big_decimal
1472
+ end
1473
+
1474
+ it_behaves_like 'a decimal128 convertible to a Ruby BigDecimal'
1475
+ end
1476
+
1477
+ context 'when the value is -12345689012345789012345' do
1478
+
1479
+ let(:big_decimal) do
1480
+ BigDecimal.new(-12345689012345789012345)
1481
+ end
1482
+
1483
+ let(:expected_big_decimal) do
1484
+ big_decimal
1485
+ end
1486
+
1487
+ it_behaves_like 'a decimal128 convertible to a Ruby BigDecimal'
1488
+ end
1489
+ end
1490
+
1491
+ context 'when the value has a fraction' do
1492
+
1493
+ context 'when the value is 0.1' do
1494
+
1495
+ let(:big_decimal) do
1496
+ BigDecimal.new(0.1, 1)
1497
+ end
1498
+
1499
+ let(:expected_big_decimal) do
1500
+ big_decimal
1501
+ end
1502
+
1503
+ it_behaves_like 'a decimal128 convertible to a Ruby BigDecimal'
1504
+ end
1505
+
1506
+ context 'when the value is -0.1' do
1507
+
1508
+ let(:big_decimal) do
1509
+ BigDecimal.new(-0.1, 1)
1510
+ end
1511
+
1512
+ let(:expected_big_decimal) do
1513
+ big_decimal
1514
+ end
1515
+
1516
+ it_behaves_like 'a decimal128 convertible to a Ruby BigDecimal'
1517
+ end
1518
+
1519
+ context 'when the value is 0.123' do
1520
+
1521
+ let(:big_decimal) do
1522
+ BigDecimal.new(0.123, 3)
1523
+ end
1524
+
1525
+ let(:expected_big_decimal) do
1526
+ big_decimal
1527
+ end
1528
+
1529
+ it_behaves_like 'a decimal128 convertible to a Ruby BigDecimal'
1530
+ end
1531
+
1532
+ context 'when the value is -0.123' do
1533
+
1534
+ let(:big_decimal) do
1535
+ BigDecimal.new(-0.123, 3)
1536
+ end
1537
+
1538
+ let(:expected_big_decimal) do
1539
+ big_decimal
1540
+ end
1541
+
1542
+ it_behaves_like 'a decimal128 convertible to a Ruby BigDecimal'
1543
+ end
1544
+ end
1545
+
1546
+ context 'when the value has leading zeros' do
1547
+
1548
+ let(:big_decimal) do
1549
+ BigDecimal.new(0.001234, 4)
1550
+ end
1551
+
1552
+ let(:expected_big_decimal) do
1553
+ big_decimal
1554
+ end
1555
+
1556
+ it_behaves_like 'a decimal128 convertible to a Ruby BigDecimal'
1557
+ end
1558
+
1559
+ context 'when the value has trailing zeros' do
1560
+
1561
+ let(:big_decimal) do
1562
+ BigDecimal.new(2.000, 4)
1563
+ end
1564
+
1565
+ let(:expected_big_decimal) do
1566
+ big_decimal
1567
+ end
1568
+
1569
+ it_behaves_like 'a decimal128 convertible to a Ruby BigDecimal'
1570
+ end
1571
+ end
1572
+
1573
+ context "when the class is loaded" do
1574
+
1575
+ let(:registered) do
1576
+ BSON::Registry.get(described_class::BSON_TYPE, 'field')
1577
+ end
1578
+
1579
+ it "registers the type" do
1580
+ expect(registered).to eq(described_class)
1581
+ end
1582
+ end
1583
+ end