amq-protocol 2.3.4 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ChangeLog.md +26 -3
- data/Gemfile +5 -0
- data/README.md +2 -7
- data/benchmarks/frame_encoding.rb +75 -0
- data/benchmarks/method_encoding.rb +198 -0
- data/benchmarks/pack_unpack.rb +158 -0
- data/benchmarks/run_all.rb +64 -0
- data/benchmarks/table_encoding.rb +110 -0
- data/lib/amq/bit_set.rb +1 -0
- data/lib/amq/endianness.rb +2 -0
- data/lib/amq/int_allocator.rb +1 -0
- data/lib/amq/pack.rb +33 -42
- data/lib/amq/protocol/constants.rb +2 -0
- data/lib/amq/protocol/exceptions.rb +3 -1
- data/lib/amq/protocol/float_32bit.rb +2 -0
- data/lib/amq/protocol/frame.rb +7 -3
- data/lib/amq/protocol/table.rb +20 -17
- data/lib/amq/protocol/table_value_decoder.rb +48 -52
- data/lib/amq/protocol/table_value_encoder.rb +1 -0
- data/lib/amq/protocol/type_constants.rb +1 -0
- data/lib/amq/protocol/version.rb +1 -1
- data/lib/amq/settings.rb +1 -0
- data/spec/amq/bit_set_spec.rb +22 -0
- data/spec/amq/endianness_spec.rb +23 -0
- data/spec/amq/int_allocator_spec.rb +26 -3
- data/spec/amq/pack_spec.rb +14 -24
- data/spec/amq/protocol/exceptions_spec.rb +70 -0
- data/spec/amq/protocol/float_32bit_spec.rb +27 -0
- data/spec/amq/protocol/frame_spec.rb +64 -0
- data/spec/amq/protocol/table_spec.rb +32 -0
- data/spec/amq/protocol/value_decoder_spec.rb +97 -0
- data/spec/amq/protocol/value_encoder_spec.rb +21 -0
- data/spec/amq/settings_spec.rb +37 -1
- data/spec/amq/uri_parsing_spec.rb +7 -0
- metadata +11 -3
data/lib/amq/bit_set.rb
CHANGED
data/lib/amq/endianness.rb
CHANGED
data/lib/amq/int_allocator.rb
CHANGED
data/lib/amq/pack.rb
CHANGED
|
@@ -1,54 +1,45 @@
|
|
|
1
1
|
# encoding: binary
|
|
2
|
-
|
|
3
|
-
require 'amq/endianness'
|
|
2
|
+
# frozen_string_literal: true
|
|
4
3
|
|
|
5
4
|
module AMQ
|
|
6
|
-
# Implements pack to/unpack from 64bit string in network byte order
|
|
7
|
-
#
|
|
5
|
+
# Implements pack to/unpack from 64bit string in network byte order.
|
|
6
|
+
# Uses native Ruby pack directives with explicit endianness (Ruby 1.9.3+).
|
|
8
7
|
module Pack
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def self.pack_int16_big_endian(short)
|
|
23
|
-
[long_long].pack(INT16)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def self.unpack_int16_big_endian(data)
|
|
27
|
-
data.unpack(INT16)
|
|
28
|
-
end
|
|
29
|
-
else
|
|
30
|
-
def self.pack_uint64_big_endian(long_long)
|
|
31
|
-
result = [long_long].pack(UINT64)
|
|
32
|
-
result.bytes.to_a.reverse.map(&:chr).join
|
|
33
|
-
end
|
|
8
|
+
# Pack format strings - frozen for performance
|
|
9
|
+
UINT64_BE = 'Q>'.freeze # 64-bit unsigned, big-endian
|
|
10
|
+
INT64_BE = 'q>'.freeze # 64-bit signed, big-endian
|
|
11
|
+
INT16_BE = 's>'.freeze # 16-bit signed, big-endian
|
|
12
|
+
UINT16_BE = 'n'.freeze # 16-bit unsigned, big-endian (network order)
|
|
13
|
+
|
|
14
|
+
# Packs a 64-bit unsigned integer to big-endian binary string.
|
|
15
|
+
# @param long_long [Integer] The value to pack
|
|
16
|
+
# @return [String] 8-byte binary string in big-endian order
|
|
17
|
+
def self.pack_uint64_big_endian(long_long)
|
|
18
|
+
[long_long].pack(UINT64_BE)
|
|
19
|
+
end
|
|
34
20
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
21
|
+
# Unpacks a big-endian binary string to a 64-bit unsigned integer.
|
|
22
|
+
# @param data [String] 8-byte binary string in big-endian order
|
|
23
|
+
# @return [Array<Integer>] Single-element array containing the unpacked value
|
|
24
|
+
def self.unpack_uint64_big_endian(data)
|
|
25
|
+
data.unpack(UINT64_BE)
|
|
26
|
+
end
|
|
39
27
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
28
|
+
# Packs a 16-bit signed integer to big-endian binary string.
|
|
29
|
+
# @param short [Integer] The value to pack
|
|
30
|
+
# @return [String] 2-byte binary string in big-endian order
|
|
31
|
+
def self.pack_int16_big_endian(short)
|
|
32
|
+
[short].pack(INT16_BE)
|
|
33
|
+
end
|
|
44
34
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
35
|
+
# Unpacks a big-endian binary string to a 16-bit signed integer.
|
|
36
|
+
# @param data [String] 2-byte binary string in big-endian order
|
|
37
|
+
# @return [Array<Integer>] Single-element array containing the unpacked value
|
|
38
|
+
def self.unpack_int16_big_endian(data)
|
|
39
|
+
data.unpack(INT16_BE)
|
|
49
40
|
end
|
|
50
41
|
end
|
|
51
42
|
|
|
52
|
-
# Backwards compatibility
|
|
43
|
+
# Backwards compatibility alias
|
|
53
44
|
Hacks = Pack
|
|
54
45
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module AMQ
|
|
2
4
|
module Protocol
|
|
3
5
|
class Error < StandardError
|
|
@@ -41,7 +43,7 @@ module AMQ
|
|
|
41
43
|
|
|
42
44
|
class BadResponseError < Protocol::Error
|
|
43
45
|
def initialize(argument, expected, actual)
|
|
44
|
-
super("Argument #{argument} has to be #{expected.inspect}, was #{
|
|
46
|
+
super("Argument #{argument} has to be #{expected.inspect}, was #{actual.inspect}")
|
|
45
47
|
end
|
|
46
48
|
end
|
|
47
49
|
|
data/lib/amq/protocol/frame.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# encoding: binary
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
module AMQ
|
|
4
5
|
module Protocol
|
|
@@ -9,6 +10,9 @@ module AMQ
|
|
|
9
10
|
CHANNEL_RANGE = (0..65535).freeze
|
|
10
11
|
FINAL_OCTET = "\xCE".freeze # 206
|
|
11
12
|
|
|
13
|
+
# Pack format for 64-bit unsigned big-endian
|
|
14
|
+
PACK_UINT64_BE = 'Q>'.freeze
|
|
15
|
+
|
|
12
16
|
def self.encoded_payload(payload)
|
|
13
17
|
if payload.respond_to?(:force_encoding) && payload.encoding.name != 'BINARY'
|
|
14
18
|
# Only copy if we have to.
|
|
@@ -130,7 +134,7 @@ This functionality is part of the https://github.com/ruby-amqp/amq-client librar
|
|
|
130
134
|
end # final?
|
|
131
135
|
|
|
132
136
|
def decode_payload
|
|
133
|
-
self.method_class.decode(@payload
|
|
137
|
+
self.method_class.decode(@payload.byteslice(4..-1))
|
|
134
138
|
end
|
|
135
139
|
end
|
|
136
140
|
|
|
@@ -167,8 +171,8 @@ This functionality is part of the https://github.com/ruby-amqp/amq-client librar
|
|
|
167
171
|
# the total size of the content body, that is, the sum of the body sizes for the
|
|
168
172
|
# following content body frames. Zero indicates that there are no content body frames.
|
|
169
173
|
# So this is NOT related to this very header frame!
|
|
170
|
-
@body_size =
|
|
171
|
-
@data = @payload
|
|
174
|
+
@body_size = @payload.byteslice(4, 8).unpack1(PACK_UINT64_BE)
|
|
175
|
+
@data = @payload.byteslice(12..-1)
|
|
172
176
|
@properties = Basic.decode_properties(@data)
|
|
173
177
|
end
|
|
174
178
|
end
|
data/lib/amq/protocol/table.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# encoding: binary
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
require "amq/protocol/type_constants"
|
|
4
5
|
require "amq/protocol/table_value_encoder"
|
|
@@ -14,6 +15,8 @@ module AMQ
|
|
|
14
15
|
|
|
15
16
|
include TypeConstants
|
|
16
17
|
|
|
18
|
+
# Pack format string
|
|
19
|
+
PACK_UINT32_BE = 'N'.freeze
|
|
17
20
|
|
|
18
21
|
#
|
|
19
22
|
# API
|
|
@@ -27,16 +30,16 @@ module AMQ
|
|
|
27
30
|
|
|
28
31
|
|
|
29
32
|
def self.encode(table)
|
|
30
|
-
buffer =
|
|
33
|
+
buffer = +''
|
|
31
34
|
|
|
32
35
|
table ||= {}
|
|
33
36
|
|
|
34
37
|
table.each do |key, value|
|
|
35
38
|
key = key.to_s # it can be a symbol as well
|
|
36
|
-
buffer << key.bytesize.chr
|
|
39
|
+
buffer << key.bytesize.chr << key
|
|
37
40
|
|
|
38
41
|
case value
|
|
39
|
-
when Hash
|
|
42
|
+
when Hash
|
|
40
43
|
buffer << TYPE_HASH
|
|
41
44
|
buffer << self.encode(value)
|
|
42
45
|
else
|
|
@@ -44,15 +47,15 @@ module AMQ
|
|
|
44
47
|
end
|
|
45
48
|
end
|
|
46
49
|
|
|
47
|
-
[buffer.bytesize].pack(
|
|
50
|
+
[buffer.bytesize].pack(PACK_UINT32_BE) << buffer
|
|
48
51
|
end
|
|
49
52
|
|
|
50
53
|
|
|
51
54
|
|
|
52
55
|
|
|
53
56
|
def self.decode(data)
|
|
54
|
-
table =
|
|
55
|
-
table_length = data.
|
|
57
|
+
table = {}
|
|
58
|
+
table_length = data.unpack1(PACK_UINT32_BE)
|
|
56
59
|
|
|
57
60
|
return table if table_length.zero?
|
|
58
61
|
|
|
@@ -86,19 +89,19 @@ module AMQ
|
|
|
86
89
|
when TYPE_BOOLEAN
|
|
87
90
|
v, offset = TableValueDecoder.decode_boolean(data, offset)
|
|
88
91
|
v
|
|
89
|
-
|
|
92
|
+
when TYPE_BYTE
|
|
90
93
|
v, offset = TableValueDecoder.decode_byte(data, offset)
|
|
91
94
|
v
|
|
92
|
-
when TYPE_SIGNED_16BIT
|
|
95
|
+
when TYPE_SIGNED_16BIT
|
|
93
96
|
v, offset = TableValueDecoder.decode_short(data, offset)
|
|
94
97
|
v
|
|
95
|
-
when TYPE_SIGNED_64BIT
|
|
98
|
+
when TYPE_SIGNED_64BIT
|
|
96
99
|
v, offset = TableValueDecoder.decode_long(data, offset)
|
|
97
100
|
v
|
|
98
|
-
when TYPE_32BIT_FLOAT
|
|
101
|
+
when TYPE_32BIT_FLOAT
|
|
99
102
|
v, offset = TableValueDecoder.decode_32bit_float(data, offset)
|
|
100
103
|
v
|
|
101
|
-
when TYPE_64BIT_FLOAT
|
|
104
|
+
when TYPE_64BIT_FLOAT
|
|
102
105
|
v, offset = TableValueDecoder.decode_64bit_float(data, offset)
|
|
103
106
|
v
|
|
104
107
|
when TYPE_VOID
|
|
@@ -112,11 +115,11 @@ module AMQ
|
|
|
112
115
|
end
|
|
113
116
|
|
|
114
117
|
table
|
|
115
|
-
end
|
|
118
|
+
end
|
|
116
119
|
|
|
117
120
|
|
|
118
121
|
def self.length(data)
|
|
119
|
-
data.
|
|
122
|
+
data.unpack1(PACK_UINT32_BE)
|
|
120
123
|
end
|
|
121
124
|
|
|
122
125
|
|
|
@@ -128,17 +131,17 @@ module AMQ
|
|
|
128
131
|
end
|
|
129
132
|
|
|
130
133
|
acc
|
|
131
|
-
end
|
|
134
|
+
end
|
|
132
135
|
|
|
133
136
|
|
|
134
137
|
def self.decode_table_key(data, offset)
|
|
135
|
-
key_length = data.
|
|
138
|
+
key_length = data.getbyte(offset)
|
|
136
139
|
offset += 1
|
|
137
|
-
key = data.
|
|
140
|
+
key = data.byteslice(offset, key_length)
|
|
138
141
|
offset += key_length
|
|
139
142
|
|
|
140
143
|
[key, offset]
|
|
141
|
-
end
|
|
144
|
+
end
|
|
142
145
|
|
|
143
146
|
|
|
144
147
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# encoding: binary
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
|
|
3
|
-
require "amq/endianness"
|
|
4
4
|
require "amq/protocol/type_constants"
|
|
5
5
|
require "amq/protocol/float_32bit"
|
|
6
6
|
|
|
@@ -15,15 +15,23 @@ module AMQ
|
|
|
15
15
|
|
|
16
16
|
include TypeConstants
|
|
17
17
|
|
|
18
|
+
# Pack format strings use explicit endianness (available as of Ruby 1.9.3)
|
|
19
|
+
PACK_UINT32_BE = 'N'.freeze
|
|
20
|
+
PACK_INT64_BE = 'q>'.freeze
|
|
21
|
+
PACK_INT16_BE = 's>'.freeze
|
|
22
|
+
PACK_UINT64_BE = 'Q>'.freeze
|
|
23
|
+
PACK_FLOAT32 = 'f'.freeze # single precision float (native endian, matches encoder)
|
|
24
|
+
PACK_FLOAT64 = 'G'.freeze # big-endian double precision float
|
|
25
|
+
PACK_UCHAR_UINT32 = 'CN'.freeze
|
|
18
26
|
|
|
19
27
|
#
|
|
20
28
|
# API
|
|
21
29
|
#
|
|
22
30
|
|
|
23
31
|
def self.decode_array(data, initial_offset)
|
|
24
|
-
array_length = data.
|
|
32
|
+
array_length = data.byteslice(initial_offset, 4).unpack1(PACK_UINT32_BE)
|
|
25
33
|
|
|
26
|
-
ary =
|
|
34
|
+
ary = []
|
|
27
35
|
offset = initial_offset + 4
|
|
28
36
|
|
|
29
37
|
while offset <= (initial_offset + array_length)
|
|
@@ -54,25 +62,25 @@ module AMQ
|
|
|
54
62
|
when TYPE_BOOLEAN
|
|
55
63
|
v, offset = decode_boolean(data, offset)
|
|
56
64
|
v
|
|
57
|
-
when TYPE_BYTE
|
|
65
|
+
when TYPE_BYTE
|
|
58
66
|
v, offset = decode_byte(data, offset)
|
|
59
67
|
v
|
|
60
|
-
when TYPE_SIGNED_16BIT
|
|
68
|
+
when TYPE_SIGNED_16BIT
|
|
61
69
|
v, offset = decode_short(data, offset)
|
|
62
70
|
v
|
|
63
|
-
when TYPE_SIGNED_64BIT
|
|
71
|
+
when TYPE_SIGNED_64BIT
|
|
64
72
|
v, offset = decode_long(data, offset)
|
|
65
73
|
v
|
|
66
|
-
when TYPE_32BIT_FLOAT
|
|
74
|
+
when TYPE_32BIT_FLOAT
|
|
67
75
|
v, offset = decode_32bit_float(data, offset)
|
|
68
76
|
v
|
|
69
|
-
when TYPE_64BIT_FLOAT
|
|
77
|
+
when TYPE_64BIT_FLOAT
|
|
70
78
|
v, offset = decode_64bit_float(data, offset)
|
|
71
79
|
v
|
|
72
80
|
when TYPE_VOID
|
|
73
81
|
nil
|
|
74
82
|
when TYPE_ARRAY
|
|
75
|
-
v, offset =
|
|
83
|
+
v, offset = decode_array(data, offset)
|
|
76
84
|
v
|
|
77
85
|
else
|
|
78
86
|
raise ArgumentError.new("unsupported type in a table value: #{type.inspect}, do not know how to decode!")
|
|
@@ -83,113 +91,101 @@ module AMQ
|
|
|
83
91
|
|
|
84
92
|
|
|
85
93
|
[ary, initial_offset + array_length + 4]
|
|
86
|
-
end
|
|
94
|
+
end
|
|
87
95
|
|
|
88
96
|
|
|
89
97
|
def self.decode_string(data, offset)
|
|
90
|
-
length = data.
|
|
98
|
+
length = data.byteslice(offset, 4).unpack1(PACK_UINT32_BE)
|
|
91
99
|
offset += 4
|
|
92
|
-
v = data.
|
|
100
|
+
v = data.byteslice(offset, length)
|
|
93
101
|
offset += length
|
|
94
102
|
|
|
95
103
|
[v, offset]
|
|
96
|
-
end
|
|
104
|
+
end
|
|
97
105
|
|
|
98
106
|
|
|
99
107
|
def self.decode_integer(data, offset)
|
|
100
|
-
v = data.
|
|
108
|
+
v = data.byteslice(offset, 4).unpack1(PACK_UINT32_BE)
|
|
101
109
|
offset += 4
|
|
102
110
|
|
|
103
111
|
[v, offset]
|
|
104
|
-
end
|
|
105
|
-
|
|
112
|
+
end
|
|
106
113
|
|
|
107
|
-
if AMQ::Endianness.big_endian?
|
|
108
|
-
def self.decode_long(data, offset)
|
|
109
|
-
v = data.slice(offset, 8).unpack(PACK_INT64)
|
|
110
114
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
def self.decode_long(data, offset)
|
|
116
|
-
slice = data.slice(offset, 8).bytes.to_a.reverse.map(&:chr).join
|
|
117
|
-
v = slice.unpack(PACK_INT64).first
|
|
118
|
-
|
|
119
|
-
offset += 8
|
|
120
|
-
[v, offset]
|
|
121
|
-
end
|
|
115
|
+
def self.decode_long(data, offset)
|
|
116
|
+
v = data.byteslice(offset, 8).unpack1(PACK_INT64_BE)
|
|
117
|
+
offset += 8
|
|
118
|
+
[v, offset]
|
|
122
119
|
end
|
|
123
120
|
|
|
124
121
|
|
|
125
122
|
def self.decode_big_decimal(data, offset)
|
|
126
|
-
decimals, raw = data.
|
|
123
|
+
decimals, raw = data.byteslice(offset, 5).unpack(PACK_UCHAR_UINT32)
|
|
127
124
|
offset += 5
|
|
128
125
|
v = BigDecimal(raw.to_s) * (BigDecimal(TEN) ** -decimals)
|
|
129
126
|
|
|
130
127
|
[v, offset]
|
|
131
|
-
end
|
|
128
|
+
end
|
|
132
129
|
|
|
133
130
|
|
|
134
131
|
def self.decode_time(data, offset)
|
|
135
|
-
timestamp = data.
|
|
132
|
+
timestamp = data.byteslice(offset, 8).unpack1(PACK_UINT64_BE)
|
|
136
133
|
v = Time.at(timestamp)
|
|
137
134
|
offset += 8
|
|
138
135
|
|
|
139
136
|
[v, offset]
|
|
140
|
-
end
|
|
137
|
+
end
|
|
141
138
|
|
|
142
139
|
|
|
143
140
|
def self.decode_boolean(data, offset)
|
|
144
|
-
|
|
141
|
+
byte = data.getbyte(offset)
|
|
145
142
|
offset += 1
|
|
146
|
-
[(
|
|
147
|
-
end
|
|
143
|
+
[(byte == 1), offset]
|
|
144
|
+
end
|
|
148
145
|
|
|
149
146
|
|
|
150
147
|
def self.decode_32bit_float(data, offset)
|
|
151
|
-
v = data.
|
|
148
|
+
v = data.byteslice(offset, 4).unpack1(PACK_FLOAT32)
|
|
152
149
|
offset += 4
|
|
153
150
|
|
|
154
151
|
[v, offset]
|
|
155
|
-
end
|
|
152
|
+
end
|
|
156
153
|
|
|
157
154
|
|
|
158
155
|
def self.decode_64bit_float(data, offset)
|
|
159
|
-
v = data.
|
|
156
|
+
v = data.byteslice(offset, 8).unpack1(PACK_FLOAT64)
|
|
160
157
|
offset += 8
|
|
161
158
|
|
|
162
159
|
[v, offset]
|
|
163
|
-
end
|
|
160
|
+
end
|
|
164
161
|
|
|
165
162
|
|
|
166
163
|
def self.decode_value_type(data, offset)
|
|
167
|
-
[data.
|
|
168
|
-
end
|
|
169
|
-
|
|
164
|
+
[data.byteslice(offset, 1), offset + 1]
|
|
165
|
+
end
|
|
170
166
|
|
|
171
167
|
|
|
172
168
|
def self.decode_hash(data, offset)
|
|
173
|
-
length = data.
|
|
174
|
-
v = Table.decode(data.
|
|
169
|
+
length = data.byteslice(offset, 4).unpack1(PACK_UINT32_BE)
|
|
170
|
+
v = Table.decode(data.byteslice(offset, length + 4))
|
|
175
171
|
offset += 4 + length
|
|
176
172
|
|
|
177
173
|
[v, offset]
|
|
178
|
-
end
|
|
174
|
+
end
|
|
179
175
|
|
|
180
176
|
|
|
181
177
|
# Decodes/Converts a byte value from the data at the provided offset.
|
|
182
178
|
#
|
|
183
|
-
# @param [
|
|
184
|
-
# @param [
|
|
185
|
-
# @return [Array] - The
|
|
179
|
+
# @param [String] data - Binary data string
|
|
180
|
+
# @param [Integer] offset - The offset from which to read the byte
|
|
181
|
+
# @return [Array] - The Integer value and new offset pair
|
|
186
182
|
def self.decode_byte(data, offset)
|
|
187
|
-
[data.
|
|
183
|
+
[data.getbyte(offset), offset + 1]
|
|
188
184
|
end
|
|
189
185
|
|
|
190
186
|
|
|
191
187
|
def self.decode_short(data, offset)
|
|
192
|
-
v =
|
|
188
|
+
v = data.byteslice(offset, 2).unpack1(PACK_INT16_BE)
|
|
193
189
|
offset += 2
|
|
194
190
|
[v, offset]
|
|
195
191
|
end
|
data/lib/amq/protocol/version.rb
CHANGED
data/lib/amq/settings.rb
CHANGED
data/spec/amq/bit_set_spec.rb
CHANGED
|
@@ -223,5 +223,27 @@ RSpec.describe AMQ::BitSet do
|
|
|
223
223
|
subject.unset(254)
|
|
224
224
|
expect(subject.get(254)).to be_falsey
|
|
225
225
|
end # it
|
|
226
|
+
|
|
227
|
+
it "returns -1 when all bits are set" do
|
|
228
|
+
bs = described_class.new(64)
|
|
229
|
+
0.upto(63) { |i| bs.set(i) }
|
|
230
|
+
expect(bs.next_clear_bit).to eq(-1)
|
|
231
|
+
end
|
|
232
|
+
end # describe
|
|
233
|
+
|
|
234
|
+
describe "#to_s" do
|
|
235
|
+
it "returns a string representation of the bit set" do
|
|
236
|
+
bs = described_class.new(64)
|
|
237
|
+
result = bs.to_s
|
|
238
|
+
expect(result).to be_a(String)
|
|
239
|
+
expect(result).to include(":")
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
it "shows set bits" do
|
|
243
|
+
bs = described_class.new(64)
|
|
244
|
+
bs.set(0)
|
|
245
|
+
result = bs.to_s
|
|
246
|
+
expect(result).to end_with("1:")
|
|
247
|
+
end
|
|
226
248
|
end # describe
|
|
227
249
|
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# encoding: binary
|
|
2
|
+
|
|
3
|
+
require "amq/endianness"
|
|
4
|
+
|
|
5
|
+
RSpec.describe AMQ::Endianness do
|
|
6
|
+
describe ".big_endian?" do
|
|
7
|
+
it "returns a boolean" do
|
|
8
|
+
expect([true, false]).to include(described_class.big_endian?)
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
describe ".little_endian?" do
|
|
13
|
+
it "returns the opposite of big_endian?" do
|
|
14
|
+
expect(described_class.little_endian?).to eq(!described_class.big_endian?)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
describe "BIG_ENDIAN constant" do
|
|
19
|
+
it "is a boolean" do
|
|
20
|
+
expect([true, false]).to include(AMQ::Endianness::BIG_ENDIAN)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -11,13 +11,17 @@ RSpec.describe AMQ::IntAllocator do
|
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
# ...
|
|
15
|
-
|
|
16
|
-
|
|
17
14
|
#
|
|
18
15
|
# Examples
|
|
19
16
|
#
|
|
20
17
|
|
|
18
|
+
describe "#initialize" do
|
|
19
|
+
it "raises ArgumentError when hi <= lo" do
|
|
20
|
+
expect { described_class.new(5, 5) }.to raise_error(ArgumentError)
|
|
21
|
+
expect { described_class.new(10, 5) }.to raise_error(ArgumentError)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
21
25
|
describe "#number_of_bits" do
|
|
22
26
|
it "returns number of bits available for allocation" do
|
|
23
27
|
expect(subject.number_of_bits).to eq(4)
|
|
@@ -110,4 +114,23 @@ RSpec.describe AMQ::IntAllocator do
|
|
|
110
114
|
end
|
|
111
115
|
end
|
|
112
116
|
end
|
|
117
|
+
|
|
118
|
+
describe "#release" do
|
|
119
|
+
it "is an alias for #free" do
|
|
120
|
+
subject.allocate
|
|
121
|
+
expect(subject.allocated?(1)).to be_truthy
|
|
122
|
+
subject.release(1)
|
|
123
|
+
expect(subject.allocated?(1)).to be_falsey
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
describe "#reset" do
|
|
128
|
+
it "releases all allocations" do
|
|
129
|
+
4.times { subject.allocate }
|
|
130
|
+
expect(subject.allocate).to eq(-1)
|
|
131
|
+
|
|
132
|
+
subject.reset
|
|
133
|
+
expect(subject.allocate).to eq(1)
|
|
134
|
+
end
|
|
135
|
+
end
|
|
113
136
|
end
|