bson 4.2.2 → 4.12.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (169) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/README.md +25 -7
  5. data/Rakefile +16 -9
  6. data/ext/bson/{native-endian.h → bson-endian.h} +5 -99
  7. data/ext/bson/bson-native.h +125 -0
  8. data/ext/bson/bytebuf.c +133 -0
  9. data/ext/bson/endian.c +117 -0
  10. data/ext/bson/init.c +355 -0
  11. data/ext/bson/libbson-utf8.c +230 -0
  12. data/ext/bson/read.c +411 -0
  13. data/ext/bson/util.c +95 -0
  14. data/ext/bson/write.c +680 -0
  15. data/lib/bson.rb +6 -3
  16. data/lib/bson/active_support.rb +17 -0
  17. data/lib/bson/array.rb +57 -17
  18. data/lib/bson/binary.rb +185 -13
  19. data/lib/bson/boolean.rb +12 -3
  20. data/lib/bson/code.rb +16 -2
  21. data/lib/bson/code_with_scope.rb +32 -5
  22. data/lib/bson/config.rb +1 -1
  23. data/lib/bson/date.rb +12 -2
  24. data/lib/bson/date_time.rb +2 -2
  25. data/lib/bson/db_pointer.rb +110 -0
  26. data/lib/bson/decimal128.rb +17 -3
  27. data/lib/bson/decimal128/builder.rb +1 -1
  28. data/lib/bson/document.rb +152 -5
  29. data/lib/bson/environment.rb +2 -1
  30. data/lib/bson/error.rb +27 -0
  31. data/lib/bson/ext_json.rb +383 -0
  32. data/lib/bson/false_class.rb +1 -1
  33. data/lib/bson/float.rb +48 -2
  34. data/lib/bson/hash.rb +68 -17
  35. data/lib/bson/int32.rb +52 -13
  36. data/lib/bson/int64.rb +59 -15
  37. data/lib/bson/integer.rb +36 -2
  38. data/lib/bson/json.rb +1 -1
  39. data/lib/bson/max_key.rb +13 -1
  40. data/lib/bson/min_key.rb +13 -1
  41. data/lib/bson/nil_class.rb +4 -2
  42. data/lib/bson/object.rb +28 -1
  43. data/lib/bson/object_id.rb +16 -2
  44. data/lib/bson/open_struct.rb +1 -1
  45. data/lib/bson/regexp.rb +27 -4
  46. data/lib/bson/registry.rb +3 -3
  47. data/lib/bson/specialized.rb +4 -2
  48. data/lib/bson/string.rb +5 -3
  49. data/lib/bson/symbol.rb +99 -7
  50. data/lib/bson/time.rb +63 -4
  51. data/lib/bson/time_with_zone.rb +54 -0
  52. data/lib/bson/timestamp.rb +44 -6
  53. data/lib/bson/true_class.rb +1 -1
  54. data/lib/bson/undefined.rb +12 -1
  55. data/lib/bson/version.rb +2 -2
  56. data/spec/bson/array_spec.rb +18 -1
  57. data/spec/bson/binary_spec.rb +100 -3
  58. data/spec/bson/binary_uuid_spec.rb +189 -0
  59. data/spec/bson/boolean_spec.rb +1 -1
  60. data/spec/bson/byte_buffer_read_spec.rb +197 -0
  61. data/spec/bson/byte_buffer_spec.rb +121 -381
  62. data/spec/bson/byte_buffer_write_spec.rb +854 -0
  63. data/spec/bson/code_spec.rb +1 -1
  64. data/spec/bson/code_with_scope_spec.rb +1 -1
  65. data/spec/bson/date_spec.rb +1 -1
  66. data/spec/bson/date_time_spec.rb +54 -1
  67. data/spec/bson/decimal128_spec.rb +35 -35
  68. data/spec/bson/document_as_spec.rb +46 -0
  69. data/spec/bson/document_spec.rb +197 -30
  70. data/spec/bson/ext_json_parse_spec.rb +308 -0
  71. data/spec/bson/false_class_spec.rb +1 -1
  72. data/spec/bson/float_spec.rb +37 -1
  73. data/spec/bson/hash_as_spec.rb +57 -0
  74. data/spec/bson/hash_spec.rb +209 -1
  75. data/spec/bson/int32_spec.rb +180 -6
  76. data/spec/bson/int64_spec.rb +199 -6
  77. data/spec/bson/integer_spec.rb +29 -3
  78. data/spec/bson/json_spec.rb +1 -1
  79. data/spec/bson/max_key_spec.rb +1 -1
  80. data/spec/bson/min_key_spec.rb +1 -1
  81. data/spec/bson/nil_class_spec.rb +1 -1
  82. data/spec/bson/object_id_spec.rb +1 -1
  83. data/spec/bson/object_spec.rb +1 -1
  84. data/spec/bson/open_struct_spec.rb +1 -1
  85. data/spec/bson/raw_spec.rb +34 -2
  86. data/spec/bson/regexp_spec.rb +1 -1
  87. data/spec/bson/registry_spec.rb +1 -1
  88. data/spec/bson/string_spec.rb +19 -1
  89. data/spec/bson/symbol_raw_spec.rb +45 -0
  90. data/spec/bson/symbol_spec.rb +63 -3
  91. data/spec/bson/time_spec.rb +205 -2
  92. data/spec/bson/time_with_zone_spec.rb +68 -0
  93. data/spec/bson/timestamp_spec.rb +56 -1
  94. data/spec/bson/true_class_spec.rb +1 -1
  95. data/spec/bson/undefined_spec.rb +1 -1
  96. data/spec/bson_spec.rb +1 -1
  97. data/spec/{support → runners}/common_driver.rb +1 -1
  98. data/spec/runners/corpus.rb +185 -0
  99. data/spec/{support/corpus.rb → runners/corpus_legacy.rb} +41 -59
  100. data/spec/spec_helper.rb +40 -3
  101. data/spec/{bson/driver_bson_spec.rb → spec_tests/common_driver_spec.rb} +1 -0
  102. data/spec/{bson/corpus_spec.rb → spec_tests/corpus_legacy_spec.rb} +10 -7
  103. data/spec/spec_tests/corpus_spec.rb +124 -0
  104. data/spec/spec_tests/data/corpus/README.md +15 -0
  105. data/spec/spec_tests/data/corpus/array.json +49 -0
  106. data/spec/spec_tests/data/corpus/binary.json +113 -0
  107. data/spec/spec_tests/data/corpus/boolean.json +27 -0
  108. data/spec/spec_tests/data/corpus/code.json +67 -0
  109. data/spec/spec_tests/data/corpus/code_w_scope.json +78 -0
  110. data/spec/spec_tests/data/corpus/datetime.json +42 -0
  111. data/spec/spec_tests/data/corpus/dbpointer.json +56 -0
  112. data/spec/spec_tests/data/corpus/dbref.json +31 -0
  113. data/spec/spec_tests/data/corpus/decimal128-1.json +317 -0
  114. data/spec/spec_tests/data/corpus/decimal128-2.json +793 -0
  115. data/spec/spec_tests/data/corpus/decimal128-3.json +1771 -0
  116. data/spec/spec_tests/data/corpus/decimal128-4.json +117 -0
  117. data/spec/spec_tests/data/corpus/decimal128-5.json +402 -0
  118. data/spec/spec_tests/data/corpus/decimal128-6.json +119 -0
  119. data/spec/spec_tests/data/corpus/decimal128-7.json +323 -0
  120. data/spec/spec_tests/data/corpus/document.json +36 -0
  121. data/spec/spec_tests/data/corpus/double.json +87 -0
  122. data/spec/spec_tests/data/corpus/int32.json +43 -0
  123. data/spec/spec_tests/data/corpus/int64.json +43 -0
  124. data/spec/spec_tests/data/corpus/maxkey.json +12 -0
  125. data/spec/spec_tests/data/corpus/minkey.json +12 -0
  126. data/spec/spec_tests/data/corpus/multi-type-deprecated.json +15 -0
  127. data/spec/spec_tests/data/corpus/multi-type.json +11 -0
  128. data/spec/spec_tests/data/corpus/null.json +12 -0
  129. data/spec/spec_tests/data/corpus/oid.json +28 -0
  130. data/spec/spec_tests/data/corpus/regex.json +65 -0
  131. data/spec/spec_tests/data/corpus/string.json +72 -0
  132. data/spec/spec_tests/data/corpus/symbol.json +80 -0
  133. data/spec/spec_tests/data/corpus/timestamp.json +34 -0
  134. data/spec/spec_tests/data/corpus/top.json +236 -0
  135. data/spec/spec_tests/data/corpus/undefined.json +15 -0
  136. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/array.json +8 -2
  137. data/spec/{support/corpus-tests/failures → spec_tests/data/corpus_legacy}/binary.json +0 -0
  138. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/boolean.json +0 -0
  139. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/code.json +1 -1
  140. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/code_w_scope.json +1 -1
  141. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/document.json +1 -1
  142. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/double.json +1 -1
  143. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/failures/datetime.json +0 -0
  144. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/failures/dbpointer.json +0 -0
  145. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/failures/int64.json +0 -0
  146. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/failures/symbol.json +0 -0
  147. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/int32.json +1 -1
  148. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/maxkey.json +1 -1
  149. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/minkey.json +1 -1
  150. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/null.json +1 -1
  151. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/oid.json +0 -0
  152. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/regex.json +1 -1
  153. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/string.json +0 -0
  154. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/timestamp.json +1 -1
  155. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/top.json +0 -0
  156. data/spec/{support/corpus-tests/failures → spec_tests/data/corpus_legacy}/undefined.json +0 -0
  157. data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-1.json +0 -0
  158. data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-2.json +0 -0
  159. data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-3.json +0 -0
  160. data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-4.json +0 -0
  161. data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-5.json +0 -0
  162. data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-6.json +0 -0
  163. data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-7.json +0 -0
  164. data/spec/support/shared_examples.rb +3 -5
  165. data/spec/support/spec_config.rb +16 -0
  166. data/spec/support/utils.rb +10 -0
  167. metadata +227 -124
  168. metadata.gz.sig +0 -0
  169. data/ext/bson/bson_native.c +0 -762
@@ -0,0 +1,54 @@
1
+ # Copyright (C) 2018-2020 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 "active_support/time_with_zone"
16
+
17
+ module BSON
18
+
19
+ # Injects behaviour for encoding ActiveSupport::TimeWithZone values to
20
+ # raw bytes as specified by the BSON spec for time.
21
+ #
22
+ # @see http://bsonspec.org/#/specification
23
+ #
24
+ # @since 4.4.0
25
+ module TimeWithZone
26
+
27
+ # Get the ActiveSupport::TimeWithZone as encoded BSON.
28
+ #
29
+ # @example Get the ActiveSupport::TimeWithZone as encoded BSON.
30
+ # Time.utc(2012, 12, 12, 0, 0, 0).in_time_zone("Pacific Time (US & Canada)").to_bson
31
+ #
32
+ # @return [ BSON::ByteBuffer ] The buffer with the encoded object.
33
+ #
34
+ # @see http://bsonspec.org/#/specification
35
+ #
36
+ # @since 4.4.0
37
+ def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?)
38
+ buffer.put_int64((to_i * 1000) + (usec / 1000))
39
+ end
40
+
41
+ # Get the BSON type for the ActiveSupport::TimeWithZone.
42
+ #
43
+ # As the ActiveSupport::TimeWithZone is converted to a time, this returns
44
+ # the BSON type for time.
45
+ def bson_type
46
+ ::Time::BSON_TYPE
47
+ end
48
+ end
49
+
50
+ # Enrich the ActiveSupport::TimeWithZone class with this module.
51
+ #
52
+ # @since 4.4.0
53
+ ActiveSupport::TimeWithZone.send(:include, TimeWithZone)
54
+ end
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2009-2014 MongoDB Inc.
1
+ # Copyright (C) 2009-2020 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.
@@ -21,12 +21,18 @@ module BSON
21
21
  # @since 2.0.0
22
22
  class Timestamp
23
23
  include JSON
24
+ include Comparable
24
25
 
25
26
  # A timestamp is type 0x11 in the BSON spec.
26
27
  #
27
28
  # @since 2.0.0
28
29
  BSON_TYPE = 17.chr.force_encoding(BINARY).freeze
29
30
 
31
+ # Error message if an object other than a Timestamp is compared with this object.
32
+ #
33
+ # @since 4.3.0
34
+ COMPARISON_ERROR_MESSAGE = 'comparison of %s with Timestamp failed'.freeze
35
+
30
36
  # @!attribute seconds
31
37
  # @return [ Integer ] The number of seconds.
32
38
  # @since 2.0.0
@@ -52,6 +58,24 @@ module BSON
52
58
  seconds == other.seconds && increment == other.increment
53
59
  end
54
60
 
61
+ # Determine if this timestamp is greater or less than another object.
62
+ #
63
+ # @example Compare the timestamp.
64
+ # timestamp < other
65
+ #
66
+ # @param [ Object ] other The object to compare against.
67
+ #
68
+ # @return [ true, false ] The result of the comparison.
69
+ #
70
+ # @since 4.3.0
71
+ def <=>(other)
72
+ raise ArgumentError.new(COMPARISON_ERROR_MESSAGE % other.class) unless other.is_a?(Timestamp)
73
+ return 0 if self == other
74
+ a = [ seconds, increment ]
75
+ b = [ other.seconds, other.increment ]
76
+ [ a, b ].sort[0] == a ? -1 : 1
77
+ end
78
+
55
79
  # Get the timestamp as JSON hash data.
56
80
  #
57
81
  # @example Get the timestamp as a JSON hash.
@@ -60,7 +84,19 @@ module BSON
60
84
  # @return [ Hash ] The timestamp as a JSON hash.
61
85
  #
62
86
  # @since 2.0.0
87
+ # @deprecated Use as_extended_json instead.
63
88
  def as_json(*args)
89
+ as_extended_json
90
+ end
91
+
92
+ # Converts this object to a representation directly serializable to
93
+ # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json.rst).
94
+ #
95
+ # @option opts [ nil | :relaxed | :legacy ] :mode Serialization mode
96
+ # (default is canonical extended JSON)
97
+ #
98
+ # @return [ Hash ] The extended json representation.
99
+ def as_extended_json(**options)
64
100
  { "$timestamp" => { "t" => seconds, "i" => increment } }
65
101
  end
66
102
 
@@ -88,22 +124,24 @@ module BSON
88
124
  #
89
125
  # @since 2.0.0
90
126
  def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?)
91
- buffer.put_int32(increment)
92
- buffer.put_int32(seconds)
127
+ buffer.put_uint32(increment)
128
+ buffer.put_uint32(seconds)
93
129
  end
94
130
 
95
131
  # Deserialize timestamp from BSON.
96
132
  #
97
133
  # @param [ ByteBuffer ] buffer The byte buffer.
98
134
  #
135
+ # @option options [ nil | :bson ] :mode Decoding mode to use.
136
+ #
99
137
  # @return [ Timestamp ] The decoded timestamp.
100
138
  #
101
139
  # @see http://bsonspec.org/#/specification
102
140
  #
103
141
  # @since 2.0.0
104
- def self.from_bson(buffer)
105
- increment = buffer.get_int32
106
- seconds = buffer.get_int32
142
+ def self.from_bson(buffer, **options)
143
+ increment = buffer.get_uint32
144
+ seconds = buffer.get_uint32
107
145
  new(seconds, increment)
108
146
  end
109
147
 
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2009-2014 MongoDB Inc.
1
+ # Copyright (C) 2009-2020 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.
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2009-2014 MongoDB Inc.
1
+ # Copyright (C) 2009-2020 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.
@@ -41,6 +41,17 @@ module BSON
41
41
  self.class == other.class
42
42
  end
43
43
 
44
+ # Converts this object to a representation directly serializable to
45
+ # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json.rst).
46
+ #
47
+ # @option opts [ nil | :relaxed | :legacy ] :mode Serialization mode
48
+ # (default is canonical extended JSON)
49
+ #
50
+ # @return [ Hash ] The extended json representation.
51
+ def as_extended_json(**options)
52
+ { "$undefined" => true }
53
+ end
54
+
44
55
  # Register this type when the module is loaded.
45
56
  #
46
57
  # @since 2.0.0
data/lib/bson/version.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2009-2016 MongoDB Inc.
1
+ # Copyright (C) 2009-2020 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.2.2".freeze
16
+ VERSION = "4.12.1".freeze
17
17
  end
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2009-2014 MongoDB Inc.
1
+ # Copyright (C) 2009-2020 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.
@@ -132,6 +132,23 @@ describe Array do
132
132
  end
133
133
  end
134
134
  end
135
+
136
+ context 'when array contains value of an unserializable class' do
137
+ class ArraySpecUnserializableClass
138
+ end
139
+
140
+ let(:obj) do
141
+ [ArraySpecUnserializableClass.new]
142
+ end
143
+
144
+ it 'raises UnserializableClass' do
145
+ lambda do
146
+ obj.to_bson
147
+ end.should raise_error(BSON::Error::UnserializableClass,
148
+ # C extension does not provide element position in the exception message.
149
+ /(Array element at position 0|Value) does not define its BSON serialized type:.*ArraySpecUnserializableClass/)
150
+ end
151
+ end
135
152
  end
136
153
 
137
154
  describe "#to_bson_normalized_value" do
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2009-2014 MongoDB Inc.
1
+ # Copyright (C) 2009-2020 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.
@@ -63,7 +63,7 @@ describe BSON::Binary do
63
63
 
64
64
  it "returns the binary data plus type" do
65
65
  expect(object.as_json).to eq(
66
- { "$binary" => Base64.encode64("testing"), "$type" => :user }
66
+ { "$binary" => {'base64' => Base64.encode64("testing").strip, "subType" => '80' }}
67
67
  )
68
68
  end
69
69
 
@@ -72,6 +72,14 @@ describe BSON::Binary do
72
72
 
73
73
  describe "#initialize" do
74
74
 
75
+ context 'when type is not given' do
76
+ let(:obj) { described_class.new('foo') }
77
+
78
+ it 'defaults to generic type' do
79
+ expect(obj.type).to eq(:generic)
80
+ end
81
+ end
82
+
75
83
  context "when he type is invalid" do
76
84
 
77
85
  it "raises an error" do
@@ -105,7 +113,11 @@ describe BSON::Binary do
105
113
  expect(object.inspect).to eq("<BSON::Binary:0x#{object.object_id} type=user data=0x1f8b08000c787055...>")
106
114
  end
107
115
 
108
- it 'is not different from default encoding' do
116
+ it 'is not binary' do
117
+ # As long as the default Ruby encoding is not binary, the inspected
118
+ # string should also not be in the binary encoding (it should be
119
+ # in one of the text encodings, but which one could depend on
120
+ # the Ruby runtime environment).
109
121
  expect(object.inspect.encoding).not_to eq(Encoding::BINARY)
110
122
  end
111
123
 
@@ -113,6 +125,37 @@ describe BSON::Binary do
113
125
 
114
126
  end
115
127
 
128
+ describe '#from_bson' do
129
+ let(:buffer) { BSON::ByteBuffer.new(bson) }
130
+ let(:obj) { described_class.from_bson(buffer) }
131
+
132
+ let(:bson) { "#{5.to_bson}#{0.chr}hello".force_encoding('BINARY') }
133
+
134
+ it 'sets data encoding to binary' do
135
+ expect(obj.data.encoding).to eq(Encoding.find('BINARY'))
136
+ end
137
+
138
+ context 'when binary subtype is supported' do
139
+ let(:bson) { [3, 0, 0, 0, 1].map(&:chr).join.force_encoding('BINARY') + 'foo' }
140
+
141
+ it 'works' do
142
+ obj.should be_a(described_class)
143
+ obj.type.should be :function
144
+ end
145
+ end
146
+
147
+ context 'when binary subtype is not supported' do
148
+ let(:bson) { [3, 0, 0, 0, 16].map(&:chr).join.force_encoding('BINARY') + 'foo' }
149
+
150
+ it 'raises an exception' do
151
+ lambda do
152
+ obj
153
+ end.should raise_error(BSON::Error::UnsupportedBinarySubtype,
154
+ /BSON data contains unsupported binary subtype 0x10/)
155
+ end
156
+ end
157
+ end
158
+
116
159
  describe "#to_bson/#from_bson" do
117
160
 
118
161
  let(:type) { 5.chr }
@@ -181,5 +224,59 @@ describe BSON::Binary do
181
224
  it_behaves_like "a serializable bson element"
182
225
  it_behaves_like "a deserializable bson element"
183
226
  end
227
+
228
+ context "when the type is :cyphertext" do
229
+ let(:obj) { described_class.new("testing", :ciphertext) }
230
+ let(:bson) { "#{7.to_bson}#{6.chr}testing" }
231
+
232
+ it_behaves_like "a serializable bson element"
233
+ it_behaves_like "a deserializable bson element"
234
+ end
235
+
236
+ context 'when given binary string' do
237
+ let(:obj) { described_class.new("\x00\xfe\xff".force_encoding('BINARY')) }
238
+ let(:bson) { "#{3.to_bson}#{0.chr}\x00\xfe\xff".force_encoding('BINARY') }
239
+
240
+ it_behaves_like "a serializable bson element"
241
+ it_behaves_like "a deserializable bson element"
242
+ end
243
+
244
+ context 'when given a frozen string' do
245
+ let(:str) { "\x00\xfe\xff".force_encoding('BINARY').freeze }
246
+ let(:obj) { described_class.new(str) }
247
+ let(:bson) { "#{3.to_bson}#{0.chr}\x00\xfe\xff".force_encoding('BINARY') }
248
+
249
+ it_behaves_like "a serializable bson element"
250
+ it_behaves_like "a deserializable bson element"
251
+ end
252
+ end
253
+
254
+ describe '#to_uuid' do
255
+ let(:obj) { described_class.new("\x00" * 16, :uuid) }
256
+
257
+ it 'accepts symbol representation' do
258
+ expect(obj.to_uuid(:standard)).to eq('00000000-0000-0000-0000-000000000000')
259
+ end
260
+
261
+ it 'rejects string representation' do
262
+ expect do
263
+ obj.to_uuid('standard')
264
+ end.to raise_error(ArgumentError, /Representation must be given as a symbol/)
265
+ end
266
+ end
267
+
268
+ describe '#from_uuid' do
269
+ let(:uuid) { '00000000-0000-0000-0000000000000000' }
270
+
271
+ it 'accepts symbol representation' do
272
+ obj = described_class.from_uuid(uuid, :standard)
273
+ expect(obj.data).to eq("\x00" * 16)
274
+ end
275
+
276
+ it 'rejects string representation' do
277
+ expect do
278
+ described_class.from_uuid(uuid, 'standard')
279
+ end.to raise_error(ArgumentError, /Representation must be given as a symbol/)
280
+ end
184
281
  end
185
282
  end
@@ -0,0 +1,189 @@
1
+ # Copyright (C) 2019-2020 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
+ require "base64"
17
+
18
+ describe "BSON::Binary - UUID spec tests" do
19
+ def make_binary(uuid_hex_str, type)
20
+ uuid_binary_str = uuid_hex_str.scan(/../).map(&:hex).map(&:chr).join
21
+ BSON::Binary.new(uuid_binary_str, type)
22
+ end
23
+
24
+ describe 'explicit encoding' do
25
+ let(:uuid_str) { '00112233-4455-6677-8899-aabbccddeeff' }
26
+
27
+ shared_examples_for 'creates binary' do
28
+ it 'creates subtype 4 binary' do
29
+ expect(binary.type).to eq(expected_type)
30
+ end
31
+
32
+ it 'creates binary with correct value' do
33
+ expect(binary.data).to eq(expected_hex_value.scan(/../).map(&:hex).map(&:chr).join)
34
+ end
35
+ end
36
+
37
+ context 'no representation' do
38
+ let(:binary) { BSON::Binary.from_uuid(uuid_str) }
39
+ let(:expected_type) { :uuid }
40
+ let(:expected_hex_value) { '00112233445566778899AABBCCDDEEFF' }
41
+
42
+ it_behaves_like 'creates binary'
43
+ end
44
+
45
+ context 'standard representation' do
46
+ let(:binary) { BSON::Binary.from_uuid(uuid_str, :standard) }
47
+ let(:expected_type) { :uuid }
48
+ let(:expected_hex_value) { '00112233445566778899AABBCCDDEEFF' }
49
+
50
+ it_behaves_like 'creates binary'
51
+ end
52
+
53
+ context 'csharp legacy representation' do
54
+ let(:binary) { BSON::Binary.from_uuid(uuid_str, :csharp_legacy) }
55
+ let(:expected_type) { :uuid_old }
56
+ let(:expected_hex_value) { '33221100554477668899AABBCCDDEEFF' }
57
+
58
+ it_behaves_like 'creates binary'
59
+ end
60
+
61
+ context 'java legacy representation' do
62
+ let(:binary) { BSON::Binary.from_uuid(uuid_str, :java_legacy) }
63
+ let(:expected_type) { :uuid_old }
64
+ let(:expected_hex_value) { '7766554433221100FFEEDDCCBBAA9988' }
65
+
66
+ it_behaves_like 'creates binary'
67
+ end
68
+
69
+ context 'python legacy representation' do
70
+ let(:binary) { BSON::Binary.from_uuid(uuid_str, :python_legacy) }
71
+ let(:expected_type) { :uuid_old }
72
+ let(:expected_hex_value) { '00112233445566778899AABBCCDDEEFF' }
73
+
74
+ it_behaves_like 'creates binary'
75
+ end
76
+ end
77
+
78
+ describe 'explicit decoding' do
79
+ context ':uuid, standard encoded' do
80
+ let(:binary) { make_binary("00112233445566778899AABBCCDDEEFF", :uuid) }
81
+
82
+ it 'decodes without arguments' do
83
+ expect(binary.to_uuid.gsub('-', '').upcase).to eq("00112233445566778899AABBCCDDEEFF")
84
+ end
85
+
86
+ it 'decodes as standard' do
87
+ expect(binary.to_uuid(:standard).gsub('-', '').upcase).to eq("00112233445566778899AABBCCDDEEFF")
88
+ end
89
+
90
+ it 'does not decode as csharp legacy' do
91
+ expect do
92
+ binary.to_uuid(:csharp_legacy)
93
+ end.to raise_error(ArgumentError, /Binary of type :uuid can only be stringified to :standard representation/)
94
+ end
95
+
96
+ it 'does not decode as java legacy' do
97
+ expect do
98
+ binary.to_uuid(:java_legacy)
99
+ end.to raise_error(ArgumentError, /Binary of type :uuid can only be stringified to :standard representation/)
100
+ end
101
+
102
+ it 'does not decode as python legacy' do
103
+ expect do
104
+ binary.to_uuid(:python_legacy)
105
+ end.to raise_error(ArgumentError, /Binary of type :uuid can only be stringified to :standard representation/)
106
+ end
107
+ end
108
+
109
+ shared_examples_for 'a legacy uuid' do
110
+ it 'does not decode without arguments' do
111
+ expect do
112
+ binary.to_uuid
113
+ end.to raise_error(ArgumentError, /Representation must be specified for BSON::Binary objects of type :uuid_old/)
114
+ end
115
+
116
+ it 'does not decode as standard' do
117
+ expect do
118
+ binary.to_uuid(:standard)
119
+ end.to raise_error(ArgumentError, /BSON::Binary objects of type :uuid_old cannot be stringified to :standard representation/)
120
+ end
121
+ end
122
+
123
+ context ':uuid_old, csharp legacy encoded' do
124
+ let(:binary) { make_binary("33221100554477668899AABBCCDDEEFF", :uuid_old) }
125
+
126
+ it_behaves_like 'a legacy uuid'
127
+
128
+ it 'decodes as csharp legacy' do
129
+ expect(binary.to_uuid(:csharp_legacy).gsub('-', '').upcase).to eq("00112233445566778899AABBCCDDEEFF")
130
+ end
131
+
132
+ it 'decodes as java legacy' do
133
+ expect(binary.to_uuid(:java_legacy).gsub('-', '').upcase).not_to eq("00112233445566778899AABBCCDDEEFF")
134
+ end
135
+
136
+ it 'decodes as python legacy' do
137
+ expect(binary.to_uuid(:python_legacy).gsub('-', '').upcase).not_to eq("00112233445566778899AABBCCDDEEFF")
138
+ end
139
+
140
+ it 'expects four dashes when output as String' do
141
+ expect(binary.to_uuid(:csharp_legacy)).to eq("00112233-4455-6677-8899-aabbccddeeff")
142
+ end
143
+ end
144
+
145
+ context ':uuid_old, java legacy encoded' do
146
+ let(:binary) { make_binary("7766554433221100FFEEDDCCBBAA9988", :uuid_old) }
147
+
148
+ it_behaves_like 'a legacy uuid'
149
+
150
+ it 'decodes as csharp legacy' do
151
+ expect(binary.to_uuid(:csharp_legacy).gsub('-', '').upcase).not_to eq("00112233445566778899AABBCCDDEEFF")
152
+ end
153
+
154
+ it 'decodes as java legacy' do
155
+ expect(binary.to_uuid(:java_legacy).gsub('-', '').upcase).to eq("00112233445566778899AABBCCDDEEFF")
156
+ end
157
+
158
+ it 'decodes as python legacy' do
159
+ expect(binary.to_uuid(:python_legacy).gsub('-', '').upcase).not_to eq("00112233445566778899AABBCCDDEEFF")
160
+ end
161
+
162
+ it 'expects four dashes when output as String' do
163
+ expect(binary.to_uuid(:java_legacy)).to eq("00112233-4455-6677-8899-aabbccddeeff")
164
+ end
165
+ end
166
+
167
+ context ':uuid_old, python legacy encoded' do
168
+ let(:binary) { make_binary("00112233445566778899AABBCCDDEEFF", :uuid_old) }
169
+
170
+ it_behaves_like 'a legacy uuid'
171
+
172
+ it 'decodes as csharp legacy' do
173
+ expect(binary.to_uuid(:csharp_legacy).gsub('-', '').upcase).not_to eq("00112233445566778899AABBCCDDEEFF")
174
+ end
175
+
176
+ it 'decodes as java legacy' do
177
+ expect(binary.to_uuid(:java_legacy).gsub('-', '').upcase).not_to eq("00112233445566778899AABBCCDDEEFF")
178
+ end
179
+
180
+ it 'decodes as python legacy' do
181
+ expect(binary.to_uuid(:python_legacy).gsub('-', '').upcase).to eq("00112233445566778899AABBCCDDEEFF")
182
+ end
183
+
184
+ it 'expects four dashes when output as String' do
185
+ expect(binary.to_uuid(:python_legacy)).to eq("00112233-4455-6677-8899-aabbccddeeff")
186
+ end
187
+ end
188
+ end
189
+ end