hexdump 0.3.0 → 1.0.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 +68 -2
- data/Gemfile +1 -0
- data/README.md +486 -135
- data/benchmark.rb +29 -22
- data/lib/hexdump/chars.rb +46 -0
- data/lib/hexdump/core_ext/file.rb +68 -6
- data/lib/hexdump/core_ext/io.rb +2 -2
- data/lib/hexdump/core_ext/kernel.rb +7 -0
- data/lib/hexdump/core_ext/string.rb +2 -2
- data/lib/hexdump/core_ext/string_io.rb +2 -2
- data/lib/hexdump/core_ext.rb +1 -0
- data/lib/hexdump/format_string.rb +43 -0
- data/lib/hexdump/hexdump.rb +768 -75
- data/lib/hexdump/mixin.rb +198 -0
- data/lib/hexdump/module_methods.rb +132 -0
- data/lib/hexdump/numeric/binary.rb +55 -0
- data/lib/hexdump/numeric/char_or_int.rb +90 -0
- data/lib/hexdump/numeric/decimal.rb +56 -0
- data/lib/hexdump/numeric/exceptions.rb +11 -0
- data/lib/hexdump/numeric/hexadecimal.rb +59 -0
- data/lib/hexdump/numeric/octal.rb +55 -0
- data/lib/hexdump/numeric.rb +5 -0
- data/lib/hexdump/reader.rb +314 -0
- data/lib/hexdump/theme/ansi.rb +81 -0
- data/lib/hexdump/theme/rule.rb +159 -0
- data/lib/hexdump/theme.rb +61 -0
- data/lib/hexdump/type.rb +232 -0
- data/lib/hexdump/types.rb +108 -0
- data/lib/hexdump/version.rb +1 -1
- data/lib/hexdump.rb +12 -1
- data/spec/chars_spec.rb +76 -0
- data/spec/core_ext_spec.rb +10 -6
- data/spec/hexdump_class_spec.rb +1708 -0
- data/spec/hexdump_module_spec.rb +23 -0
- data/spec/mixin_spec.rb +37 -0
- data/spec/numeric/binary_spec.rb +239 -0
- data/spec/numeric/char_or_int_spec.rb +210 -0
- data/spec/numeric/decimal_spec.rb +317 -0
- data/spec/numeric/hexadecimal_spec.rb +320 -0
- data/spec/numeric/octal_spec.rb +239 -0
- data/spec/reader_spec.rb +863 -0
- data/spec/theme/ansi_spec.rb +242 -0
- data/spec/theme/rule_spec.rb +199 -0
- data/spec/theme_spec.rb +94 -0
- data/spec/type_spec.rb +317 -0
- data/spec/types_spec.rb +904 -0
- metadata +39 -10
- data/.gemtest +0 -0
- data/lib/hexdump/dumper.rb +0 -419
- data/spec/dumper_spec.rb +0 -329
- data/spec/hexdump_spec.rb +0 -30
@@ -0,0 +1,239 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'hexdump/numeric/octal'
|
3
|
+
require 'hexdump/type'
|
4
|
+
|
5
|
+
describe Hexdump::Numeric::Octal do
|
6
|
+
describe "#initialize" do
|
7
|
+
subject { described_class.new(type) }
|
8
|
+
|
9
|
+
context "when given a Type::Int type" do
|
10
|
+
context "and size is 1" do
|
11
|
+
let(:type) { Hexdump::Type::Int8.new }
|
12
|
+
|
13
|
+
it "must set #width to 3 + 1" do
|
14
|
+
expect(subject.width).to eq(3 + 1)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context "and size is 2" do
|
19
|
+
let(:type) { Hexdump::Type::Int16.new }
|
20
|
+
|
21
|
+
it "must set #width to 6 + 1" do
|
22
|
+
expect(subject.width).to eq(6 + 1)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "and size is 4" do
|
27
|
+
let(:type) { Hexdump::Type::Int32.new }
|
28
|
+
|
29
|
+
it "must set #width to 11 + 1" do
|
30
|
+
expect(subject.width).to eq(11 + 1)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context "and size is 8" do
|
35
|
+
let(:type) { Hexdump::Type::Int64.new }
|
36
|
+
|
37
|
+
it "must set #width to 22 + 1" do
|
38
|
+
expect(subject.width).to eq(22 + 1)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context "but the type has an unsupported size" do
|
43
|
+
class UnsupportedIntType < Hexdump::Type::Int
|
44
|
+
|
45
|
+
def initialize
|
46
|
+
super(size: 3)
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
let(:type) { UnsupportedIntType.new }
|
52
|
+
|
53
|
+
it do
|
54
|
+
expect { described_class.new(type) }.to raise_error(NotImplementedError)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context "when given a Type::UInt type" do
|
60
|
+
context "and size is 1" do
|
61
|
+
let(:type) { Hexdump::Type::UInt8.new }
|
62
|
+
|
63
|
+
it "must set #width to 3" do
|
64
|
+
expect(subject.width).to eq(3)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context "and size is 2" do
|
69
|
+
let(:type) { Hexdump::Type::UInt16.new }
|
70
|
+
|
71
|
+
it "must set #width to 6" do
|
72
|
+
expect(subject.width).to eq(6)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context "and size is 4" do
|
77
|
+
let(:type) { Hexdump::Type::UInt32.new }
|
78
|
+
|
79
|
+
it "must set #width to 11" do
|
80
|
+
expect(subject.width).to eq(11)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context "and size is 8" do
|
85
|
+
let(:type) { Hexdump::Type::UInt64.new }
|
86
|
+
|
87
|
+
it "must set #width to 22" do
|
88
|
+
expect(subject.width).to eq(22)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context "but the type has an unsupported size" do
|
93
|
+
class UnsupportedUIntType < Hexdump::Type::UInt
|
94
|
+
|
95
|
+
def initialize
|
96
|
+
super(size: 3)
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
let(:type) { UnsupportedUIntType.new }
|
102
|
+
|
103
|
+
it do
|
104
|
+
expect { described_class.new(type) }.to raise_error(NotImplementedError)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context "when given a Type::Float type" do
|
110
|
+
let(:type) { Hexdump::Type::Float32.new }
|
111
|
+
|
112
|
+
it do
|
113
|
+
expect {
|
114
|
+
described_class.new(type)
|
115
|
+
}.to raise_error(Hexdump::Numeric::IncompatibleTypeError,"cannot format floating-point numbers in octal")
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
context "when given a non-Type object" do
|
120
|
+
let(:type) { Object.new }
|
121
|
+
|
122
|
+
it do
|
123
|
+
expect { described_class.new(type) }.to raise_error(TypeError)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe "#%" do
|
129
|
+
subject { described_class.new(type) }
|
130
|
+
|
131
|
+
context "when the given type has size 1" do
|
132
|
+
let(:type) { Hexdump::Type::UInt8.new }
|
133
|
+
|
134
|
+
let(:value) { 0xf }
|
135
|
+
let(:octal) { '017' }
|
136
|
+
|
137
|
+
it "must return a octal string of length 8" do
|
138
|
+
expect(subject % value).to eq(octal)
|
139
|
+
end
|
140
|
+
|
141
|
+
context "and is signed" do
|
142
|
+
let(:type) { Hexdump::Type::Int8.new }
|
143
|
+
|
144
|
+
context "and the value is positive" do
|
145
|
+
it "must return a octal string of length 8 prefixed with a ' '" do
|
146
|
+
expect(subject % value).to eq(" #{octal}")
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
context "and the value is negative" do
|
151
|
+
it "must return a octal string of length 8 prefixed with a '-'" do
|
152
|
+
expect(subject % -value).to eq("-#{octal}")
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
context "when the given type has size 2" do
|
159
|
+
let(:type) { Hexdump::Type::UInt16.new }
|
160
|
+
|
161
|
+
let(:value) { 0xff }
|
162
|
+
let(:octal) { '000377' }
|
163
|
+
|
164
|
+
it "must return a octal string of length 16" do
|
165
|
+
expect(subject % value).to eq(octal)
|
166
|
+
end
|
167
|
+
|
168
|
+
context "and is signed" do
|
169
|
+
let(:type) { Hexdump::Type::Int16.new }
|
170
|
+
|
171
|
+
context "and the value is positive" do
|
172
|
+
it "must return a octal string of length 16 prefixed with a ' '" do
|
173
|
+
expect(subject % value).to eq(" #{octal}")
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
context "and the value is negative" do
|
178
|
+
it "must return a octal string of length 16 prefixed with a '-'" do
|
179
|
+
expect(subject % -value).to eq("-#{octal}")
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
context "when the given type has size 4" do
|
186
|
+
let(:type) { Hexdump::Type::UInt32.new }
|
187
|
+
|
188
|
+
let(:value) { 0xffff }
|
189
|
+
let(:octal) { '00000177777' }
|
190
|
+
|
191
|
+
it "must return a octal string of length 32" do
|
192
|
+
expect(subject % value).to eq(octal)
|
193
|
+
end
|
194
|
+
|
195
|
+
context "and is signed" do
|
196
|
+
let(:type) { Hexdump::Type::Int32.new }
|
197
|
+
|
198
|
+
context "and the value is positive" do
|
199
|
+
it "must return a octal string of length 32 prefixed with a ' '" do
|
200
|
+
expect(subject % value).to eq(" #{octal}")
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
context "and the value is negative" do
|
205
|
+
it "must return a octal string of length 32 prefixed with a '-'" do
|
206
|
+
expect(subject % -value).to eq("-#{octal}")
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
context "when the given type has size 8" do
|
213
|
+
let(:type) { Hexdump::Type::UInt64.new }
|
214
|
+
|
215
|
+
let(:value) { 0xffffffff }
|
216
|
+
let(:octal) { '0000000000037777777777' }
|
217
|
+
|
218
|
+
it "must return a octal string of length 64" do
|
219
|
+
expect(subject % value).to eq(octal)
|
220
|
+
end
|
221
|
+
|
222
|
+
context "and is signed" do
|
223
|
+
let(:type) { Hexdump::Type::Int64.new }
|
224
|
+
|
225
|
+
context "and the value is positive" do
|
226
|
+
it "must return a octal string of length 64 prefixed with a ' '" do
|
227
|
+
expect(subject % value).to eq(" #{octal}")
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
context "and the value is negative" do
|
232
|
+
it "must return a octal string of length 64 prefixed with a '-'" do
|
233
|
+
expect(subject % -value).to eq("-#{octal}")
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
data/spec/reader_spec.rb
ADDED
@@ -0,0 +1,863 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'hexdump/reader'
|
3
|
+
require 'hexdump/types'
|
4
|
+
|
5
|
+
describe Hexdump::Reader do
|
6
|
+
describe "#initialize" do
|
7
|
+
let(:type) { Hexdump::TYPES[:uint8] }
|
8
|
+
|
9
|
+
subject { described_class.new(type) }
|
10
|
+
|
11
|
+
it "must set #type" do
|
12
|
+
expect(subject.type).to eq(type)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "must default #offset to nil" do
|
16
|
+
expect(subject.offset).to be(nil)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "must default #length to nil" do
|
20
|
+
expect(subject.length).to be(nil)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "must default #zero_pad? to false" do
|
24
|
+
expect(subject.zero_pad?).to be(false)
|
25
|
+
end
|
26
|
+
|
27
|
+
context "when offset: is given" do
|
28
|
+
let(:offset) { 2 }
|
29
|
+
|
30
|
+
subject { described_class.new(type, offset: offset) }
|
31
|
+
|
32
|
+
it "must set #offset" do
|
33
|
+
expect(subject.offset).to eq(offset)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "when length: is given" do
|
38
|
+
let(:length) { 256 }
|
39
|
+
|
40
|
+
subject { described_class.new(type, length: length) }
|
41
|
+
|
42
|
+
it "must set #length" do
|
43
|
+
expect(subject.length).to eq(length)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "when zero_pad: is true" do
|
48
|
+
subject { described_class.new(type, zero_pad: true) }
|
49
|
+
|
50
|
+
it "must enable #zero_pad?" do
|
51
|
+
expect(subject.zero_pad?).to be(true)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "#each_byte" do
|
57
|
+
let(:type) { Hexdump::TYPES[:uint8] }
|
58
|
+
|
59
|
+
subject { described_class.new(type) }
|
60
|
+
|
61
|
+
let(:chars) { %w[A B C D] }
|
62
|
+
let(:data) { chars.join }
|
63
|
+
let(:bytes) { data.bytes }
|
64
|
+
|
65
|
+
it "must yield each byte from the given data" do
|
66
|
+
expect { |b|
|
67
|
+
subject.each_byte(data,&b)
|
68
|
+
}.to yield_successive_args(*bytes)
|
69
|
+
end
|
70
|
+
|
71
|
+
context "when #offset is > 0" do
|
72
|
+
let(:offset) { 2 }
|
73
|
+
let(:bytes) { data.bytes[offset..-1] }
|
74
|
+
|
75
|
+
subject { described_class.new(type, offset: offset) }
|
76
|
+
|
77
|
+
it "must offset the first N bytes before yielding any bytes" do
|
78
|
+
expect { |b|
|
79
|
+
subject.each_byte(data,&b)
|
80
|
+
}.to yield_successive_args(*bytes)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context "when #length is set" do
|
85
|
+
let(:length) { 3 }
|
86
|
+
let(:bytes) { data.bytes[0,length] }
|
87
|
+
|
88
|
+
subject { described_class.new(type, length: length) }
|
89
|
+
|
90
|
+
it "must read at most N bytes" do
|
91
|
+
expect { |b|
|
92
|
+
subject.each_byte(data,&b)
|
93
|
+
}.to yield_successive_args(*bytes)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context "when no block is given" do
|
98
|
+
it "must return an Enumerator" do
|
99
|
+
expect(subject.each_byte(data)).to be_kind_of(Enumerator)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe "#each_slice" do
|
105
|
+
context "when type has size of 1" do
|
106
|
+
let(:type) { Hexdump::TYPES[:int8] }
|
107
|
+
let(:chars) { %w[A B C D] }
|
108
|
+
let(:data) { "ABCD" }
|
109
|
+
|
110
|
+
subject { described_class.new(type) }
|
111
|
+
|
112
|
+
it "must yield each consequetize character" do
|
113
|
+
expect { |b|
|
114
|
+
subject.each_slice(data,&b)
|
115
|
+
}.to yield_successive_args(*chars)
|
116
|
+
end
|
117
|
+
|
118
|
+
context "and when #offset is > 0" do
|
119
|
+
let(:offset) { 2 }
|
120
|
+
let(:chars) { %w[C D] }
|
121
|
+
|
122
|
+
subject { described_class.new(type, offset: offset) }
|
123
|
+
|
124
|
+
it "must offset the first N bytes before reading each character" do
|
125
|
+
expect { |b|
|
126
|
+
subject.each_slice(data,&b)
|
127
|
+
}.to yield_successive_args(*chars)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context "and when #length is set" do
|
132
|
+
let(:length) { 3 }
|
133
|
+
let(:chars) { %w[A B C] }
|
134
|
+
|
135
|
+
subject { described_class.new(type, length: length) }
|
136
|
+
|
137
|
+
it "must read at most N bytes" do
|
138
|
+
expect { |b|
|
139
|
+
subject.each_slice(data,&b)
|
140
|
+
}.to yield_successive_args(*chars)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
context "when type has size > 1" do
|
146
|
+
let(:type) { Hexdump::TYPES[:int16] }
|
147
|
+
let(:slices) { %w[AA BB CC DD EE FF] }
|
148
|
+
let(:data) { "AABBCCDDEEFF" }
|
149
|
+
|
150
|
+
subject { described_class.new(type) }
|
151
|
+
|
152
|
+
it "must yield each slice of the String" do
|
153
|
+
expect { |b|
|
154
|
+
subject.each_slice(data,&b)
|
155
|
+
}.to yield_successive_args(*slices)
|
156
|
+
end
|
157
|
+
|
158
|
+
it "must yield a new String instance for each slice" do
|
159
|
+
yielded_object_ids = []
|
160
|
+
|
161
|
+
subject.each_slice(data) do |slice|
|
162
|
+
yielded_object_ids << slice.object_id
|
163
|
+
end
|
164
|
+
|
165
|
+
expect(yielded_object_ids.uniq).to eq(yielded_object_ids)
|
166
|
+
end
|
167
|
+
|
168
|
+
context "and when #offset is > 0" do
|
169
|
+
let(:offset) { 3 }
|
170
|
+
let(:slices) { %w[BC CD DE EF F] }
|
171
|
+
|
172
|
+
subject { described_class.new(type, offset: offset) }
|
173
|
+
|
174
|
+
it "must offset the first N bytes before reading each slice" do
|
175
|
+
expect { |b|
|
176
|
+
subject.each_slice(data,&b)
|
177
|
+
}.to yield_successive_args(*slices)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
context "and when #length is set" do
|
182
|
+
let(:length) { 7 }
|
183
|
+
let(:slices) { %w[AA BB CC D] }
|
184
|
+
|
185
|
+
subject { described_class.new(type, length: length) }
|
186
|
+
|
187
|
+
it "must read at most N bytes" do
|
188
|
+
expect { |b|
|
189
|
+
subject.each_slice(data,&b)
|
190
|
+
}.to yield_successive_args(*slices)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
context "when the given data is not evenly divisible by the type's size" do
|
195
|
+
let(:type) { Hexdump::TYPES[:int32] }
|
196
|
+
let(:slices) { %w[AABB CCDD E] }
|
197
|
+
let(:data) { "AABBCCDDE" }
|
198
|
+
|
199
|
+
it "must yield the reamining data" do
|
200
|
+
expect { |b|
|
201
|
+
subject.each_slice(data,&b)
|
202
|
+
}.to yield_successive_args('AABB', 'CCDD', "E")
|
203
|
+
end
|
204
|
+
|
205
|
+
context "but #zero_pad? is true" do
|
206
|
+
subject { described_class.new(type, zero_pad: true) }
|
207
|
+
|
208
|
+
it "must zero out the rest of the buffer" do
|
209
|
+
expect { |b|
|
210
|
+
subject.each_slice(data,&b)
|
211
|
+
}.to yield_successive_args('AABB', 'CCDD', "E\0\0\0")
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
describe "#each_uint" do
|
219
|
+
context "when the type has size of 1" do
|
220
|
+
let(:bytes) { [0x41, 0x42, 0x43, 0x44] }
|
221
|
+
let(:raw) { bytes.map(&:chr) }
|
222
|
+
let(:data) { raw.join }
|
223
|
+
let(:type) { Hexdump::TYPES[:int8] }
|
224
|
+
|
225
|
+
subject { described_class.new(type) }
|
226
|
+
|
227
|
+
it "must yield each byte" do
|
228
|
+
expect { |b|
|
229
|
+
subject.each_uint(data,&b)
|
230
|
+
}.to yield_successive_args(*raw.zip(bytes))
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
context "when the type has size of 2" do
|
235
|
+
let(:uints) { [0xfa01, 0xfb02, 0xfc03, 0xfd04] }
|
236
|
+
|
237
|
+
context "when the type is little-endian" do
|
238
|
+
let(:type) { Hexdump::TYPES[:uint16_le] }
|
239
|
+
let(:raw) { uints.map { |uint| [uint].pack('S<') } }
|
240
|
+
let(:data) { raw.join }
|
241
|
+
|
242
|
+
subject { described_class.new(type) }
|
243
|
+
|
244
|
+
it "must decode the bytes in little-endian order" do
|
245
|
+
expect { |b|
|
246
|
+
subject.each_uint(data,&b)
|
247
|
+
}.to yield_successive_args(*raw.zip(uints))
|
248
|
+
end
|
249
|
+
|
250
|
+
context "but there is not enough bytes to decode a value" do
|
251
|
+
let(:data) { "\x11".encode(Encoding::BINARY) }
|
252
|
+
|
253
|
+
it "must yield remaining bytes and nil" do
|
254
|
+
expect { |b|
|
255
|
+
subject.each_uint(data,&b)
|
256
|
+
}.to yield_with_args(data,nil)
|
257
|
+
end
|
258
|
+
|
259
|
+
context "but #zero_pad? is true" do
|
260
|
+
subject { described_class.new(type, zero_pad: true) }
|
261
|
+
|
262
|
+
it "must yield the zero-padded data and partially decoded uint" do
|
263
|
+
expect { |b|
|
264
|
+
subject.each_uint(data,&b)
|
265
|
+
}.to yield_with_args("#{data}\x00",0x0011)
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
context "when the type is big-endian" do
|
272
|
+
let(:type) { Hexdump::TYPES[:uint16_be] }
|
273
|
+
let(:raw) { uints.map { |uint| [uint].pack('S>') } }
|
274
|
+
let(:data) { raw.join }
|
275
|
+
|
276
|
+
subject { described_class.new(type) }
|
277
|
+
|
278
|
+
it "must decode the bytes in big-endian order" do
|
279
|
+
expect { |b|
|
280
|
+
subject.each_uint(data,&b)
|
281
|
+
}.to yield_successive_args(*raw.zip(uints))
|
282
|
+
end
|
283
|
+
|
284
|
+
context "but there is not enough bytes to decode a value" do
|
285
|
+
let(:data) { "\x11".encode(Encoding::BINARY) }
|
286
|
+
|
287
|
+
it "must yield remaining bytes and nil" do
|
288
|
+
expect { |b|
|
289
|
+
subject.each_uint(data,&b)
|
290
|
+
}.to yield_with_args(data,nil)
|
291
|
+
end
|
292
|
+
|
293
|
+
context "but #zero_pad? is true" do
|
294
|
+
subject { described_class.new(type, zero_pad: true) }
|
295
|
+
|
296
|
+
it "must yield the zero-padded data and partially decoded uint" do
|
297
|
+
expect { |b|
|
298
|
+
subject.each_uint(data,&b)
|
299
|
+
}.to yield_with_args("#{data}\x00",0x1100)
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
context "when the type has size of 4" do
|
307
|
+
let(:uints) { [0xffeedd01, 0xffccbb02, 0xffaa9903, 0xff887704] }
|
308
|
+
|
309
|
+
context "when the type is little-endian" do
|
310
|
+
let(:type) { Hexdump::TYPES[:uint32_le] }
|
311
|
+
let(:raw) { uints.map { |uint| [uint].pack('L<') } }
|
312
|
+
let(:data) { raw.join }
|
313
|
+
|
314
|
+
subject { described_class.new(type) }
|
315
|
+
|
316
|
+
it "must decode the bytes in little-endian order" do
|
317
|
+
expect { |b|
|
318
|
+
subject.each_uint(data,&b)
|
319
|
+
}.to yield_successive_args(*raw.zip(uints))
|
320
|
+
end
|
321
|
+
|
322
|
+
context "but there is not enough bytes to decode a value" do
|
323
|
+
let(:data) { "\x11\x22\x33".encode(Encoding::BINARY) }
|
324
|
+
|
325
|
+
it "must yield nil and the remaining bytes" do
|
326
|
+
expect { |b|
|
327
|
+
subject.each_uint(data,&b)
|
328
|
+
}.to yield_with_args(data,nil)
|
329
|
+
end
|
330
|
+
|
331
|
+
context "but #zero_pad? is true" do
|
332
|
+
subject { described_class.new(type, zero_pad: true) }
|
333
|
+
|
334
|
+
it "must yield the zero-padded data and partially decoded uint" do
|
335
|
+
expect { |b|
|
336
|
+
subject.each_uint(data,&b)
|
337
|
+
}.to yield_with_args("#{data}\x00",0x00332211)
|
338
|
+
end
|
339
|
+
end
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
context "when the type is big-endian" do
|
344
|
+
let(:type) { Hexdump::TYPES[:uint32_be] }
|
345
|
+
let(:raw) { uints.map { |uint| [uint].pack('L>') } }
|
346
|
+
let(:data) { raw.join }
|
347
|
+
|
348
|
+
subject { described_class.new(type) }
|
349
|
+
|
350
|
+
it "must decode the bytes in big-endian order" do
|
351
|
+
expect { |b|
|
352
|
+
subject.each_uint(data,&b)
|
353
|
+
}.to yield_successive_args(*raw.zip(uints))
|
354
|
+
end
|
355
|
+
|
356
|
+
context "but there is not enough bytes to decode a value" do
|
357
|
+
let(:data) { "\x11\x22\x33".encode(Encoding::BINARY) }
|
358
|
+
|
359
|
+
it "must yield the remaining bytes and nil" do
|
360
|
+
expect { |b|
|
361
|
+
subject.each_uint(data,&b)
|
362
|
+
}.to yield_with_args(data,nil)
|
363
|
+
end
|
364
|
+
|
365
|
+
context "but #zero_pad? is true" do
|
366
|
+
subject { described_class.new(type, zero_pad: true) }
|
367
|
+
|
368
|
+
it "must yield the zero-padded data and partially decoded uint" do
|
369
|
+
expect { |b|
|
370
|
+
subject.each_uint(data,&b)
|
371
|
+
}.to yield_with_args("#{data}\x00",0x11223300)
|
372
|
+
end
|
373
|
+
end
|
374
|
+
end
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
context "when the type has size of 8" do
|
379
|
+
let(:uints) { [0xffffffff11223344, 0xffffffff55667788, 0xffffffff99aabbcc, 0xffffffffddeeff00] }
|
380
|
+
|
381
|
+
context "when the type is little-endian" do
|
382
|
+
let(:type) { Hexdump::TYPES[:uint64_le] }
|
383
|
+
let(:raw) { uints.map { |uint| [uint].pack('Q<') } }
|
384
|
+
let(:data) { raw.join }
|
385
|
+
|
386
|
+
subject { described_class.new(type) }
|
387
|
+
|
388
|
+
it "must decode the bytes in little-endian order" do
|
389
|
+
expect { |b|
|
390
|
+
subject.each_uint(data,&b)
|
391
|
+
}.to yield_successive_args(*raw.zip(uints))
|
392
|
+
end
|
393
|
+
|
394
|
+
context "but there is not enough bytes to decode a value" do
|
395
|
+
let(:data) { "\x11\x22\x33\x44\x55\x66\x77".encode(Encoding::BINARY) }
|
396
|
+
|
397
|
+
it "must yield the remaining bytes and nil" do
|
398
|
+
expect { |b|
|
399
|
+
subject.each_uint(data,&b)
|
400
|
+
}.to yield_with_args(data,nil)
|
401
|
+
end
|
402
|
+
|
403
|
+
context "but #zero_pad? is true" do
|
404
|
+
subject { described_class.new(type, zero_pad: true) }
|
405
|
+
|
406
|
+
it "must yield the zero-padded data and partially decoded uint" do
|
407
|
+
expect { |b|
|
408
|
+
subject.each_uint(data,&b)
|
409
|
+
}.to yield_with_args("#{data}\x00",0x0077665544332211)
|
410
|
+
end
|
411
|
+
end
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
415
|
+
context "when the type is big-endian" do
|
416
|
+
let(:type) { Hexdump::TYPES[:uint64_be] }
|
417
|
+
let(:raw) { uints.map { |uint| [uint].pack('Q>') } }
|
418
|
+
let(:data) { raw.join }
|
419
|
+
|
420
|
+
subject { described_class.new(type) }
|
421
|
+
|
422
|
+
it "must decode the bytes in big-endian order" do
|
423
|
+
expect { |b|
|
424
|
+
subject.each_uint(data,&b)
|
425
|
+
}.to yield_successive_args(*raw.zip(uints))
|
426
|
+
end
|
427
|
+
|
428
|
+
context "but there is not enough bytes to decode a value" do
|
429
|
+
let(:data) { "\x11\x22\x33\x44\x55\x66\x77".encode(Encoding::BINARY) }
|
430
|
+
|
431
|
+
it "must yield the remaining bytes and nil" do
|
432
|
+
expect { |b|
|
433
|
+
subject.each_uint(data,&b)
|
434
|
+
}.to yield_with_args(data,nil)
|
435
|
+
end
|
436
|
+
|
437
|
+
context "but #zero_pad? is true" do
|
438
|
+
subject { described_class.new(type, zero_pad: true) }
|
439
|
+
|
440
|
+
it "must yield the zero-padded data and partially decoded uint" do
|
441
|
+
expect { |b|
|
442
|
+
subject.each_uint(data,&b)
|
443
|
+
}.to yield_with_args("#{data}\x00",0x1122334455667700)
|
444
|
+
end
|
445
|
+
end
|
446
|
+
end
|
447
|
+
end
|
448
|
+
end
|
449
|
+
|
450
|
+
context "when the given data does not define #each_byte" do
|
451
|
+
it do
|
452
|
+
expect {
|
453
|
+
subject.each_uint(Object.new).to_a
|
454
|
+
}.to raise_error(ArgumentError)
|
455
|
+
end
|
456
|
+
end
|
457
|
+
end
|
458
|
+
|
459
|
+
describe "#each_int" do
|
460
|
+
context "when the type has size of 1" do
|
461
|
+
let(:ints) { [0x01, -0x02, 0x03, -0x04] }
|
462
|
+
let(:type) { Hexdump::TYPES[:int8] }
|
463
|
+
let(:raw) { ints.map { |int| [int].pack('c') } }
|
464
|
+
let(:data) { raw.join }
|
465
|
+
|
466
|
+
subject { described_class.new(type) }
|
467
|
+
|
468
|
+
it "must decode the bytes" do
|
469
|
+
expect { |b|
|
470
|
+
subject.each_int(data,&b)
|
471
|
+
}.to yield_successive_args(*raw.zip(ints))
|
472
|
+
end
|
473
|
+
end
|
474
|
+
|
475
|
+
context "when the type has size of 2" do
|
476
|
+
let(:ints) { [0x0001, -0x0002, 0x0003, -0x0004] }
|
477
|
+
|
478
|
+
context "when the type is little-endian" do
|
479
|
+
let(:type) { Hexdump::TYPES[:int16_le] }
|
480
|
+
let(:raw) { ints.map { |int| [int].pack('s<') } }
|
481
|
+
let(:data) { raw.join }
|
482
|
+
|
483
|
+
subject { described_class.new(type) }
|
484
|
+
|
485
|
+
it "must decode the bytes in little-endian order" do
|
486
|
+
expect { |b|
|
487
|
+
subject.each_int(data,&b)
|
488
|
+
}.to yield_successive_args(*raw.zip(ints))
|
489
|
+
end
|
490
|
+
|
491
|
+
context "but there is not enough bytes to decode a value" do
|
492
|
+
let(:data) { "\x01".encode(Encoding::BINARY) }
|
493
|
+
|
494
|
+
it "must yield the remaining bytes and nil" do
|
495
|
+
expect { |b|
|
496
|
+
subject.each_int(data,&b)
|
497
|
+
}.to yield_with_args(data, nil)
|
498
|
+
end
|
499
|
+
|
500
|
+
context "but #zero_pad? is true" do
|
501
|
+
subject { described_class.new(type, zero_pad: true) }
|
502
|
+
|
503
|
+
it "must yield the zero-padded data and partially decoded int" do
|
504
|
+
expect { |b|
|
505
|
+
subject.each_int(data,&b)
|
506
|
+
}.to yield_with_args("#{data}\x00",0x01)
|
507
|
+
end
|
508
|
+
end
|
509
|
+
end
|
510
|
+
end
|
511
|
+
|
512
|
+
context "when the type is big-endian" do
|
513
|
+
let(:type) { Hexdump::TYPES[:int16_be] }
|
514
|
+
let(:raw) { ints.map { |int| [int].pack('s>') } }
|
515
|
+
let(:data) { raw.join }
|
516
|
+
|
517
|
+
subject { described_class.new(type) }
|
518
|
+
|
519
|
+
it "must decode the bytes in big-endian order" do
|
520
|
+
expect { |b|
|
521
|
+
subject.each_int(data,&b)
|
522
|
+
}.to yield_successive_args(*raw.zip(ints))
|
523
|
+
end
|
524
|
+
|
525
|
+
context "but there is not enough bytes to decode a value" do
|
526
|
+
let(:data) { "\x01".encode(Encoding::BINARY) }
|
527
|
+
|
528
|
+
it "must yield the remaining bytes and nil" do
|
529
|
+
expect { |b|
|
530
|
+
subject.each_int(data,&b)
|
531
|
+
}.to yield_with_args(data, nil)
|
532
|
+
end
|
533
|
+
|
534
|
+
context "but #zero_pad? is true" do
|
535
|
+
subject { described_class.new(type, zero_pad: true) }
|
536
|
+
|
537
|
+
it "must yield the zero-padded data and partially decoded int" do
|
538
|
+
expect { |b|
|
539
|
+
subject.each_int(data,&b)
|
540
|
+
}.to yield_with_args("#{data}\x00",0x0100)
|
541
|
+
end
|
542
|
+
end
|
543
|
+
end
|
544
|
+
end
|
545
|
+
end
|
546
|
+
|
547
|
+
context "when the type has size of 4" do
|
548
|
+
let(:ints) { [0x00aa0001, -0x00bb0002, 0x00cc0003, -0x00dd0004] }
|
549
|
+
|
550
|
+
context "when the type is little-endian" do
|
551
|
+
let(:type) { Hexdump::TYPES[:int32_le] }
|
552
|
+
let(:raw) { ints.map { |int| [int].pack('l<') } }
|
553
|
+
let(:data) { raw.join }
|
554
|
+
|
555
|
+
subject { described_class.new(type) }
|
556
|
+
|
557
|
+
it "must decode the bytes in little-endian order" do
|
558
|
+
expect { |b|
|
559
|
+
subject.each_int(data,&b)
|
560
|
+
}.to yield_successive_args(*raw.zip(ints))
|
561
|
+
end
|
562
|
+
|
563
|
+
context "but there is not enough bytes to decode a value" do
|
564
|
+
let(:data) { "\x01\x02\x03".encode(Encoding::BINARY) }
|
565
|
+
|
566
|
+
it "must yield the remaining bytes and nil" do
|
567
|
+
expect { |b|
|
568
|
+
subject.each_int(data,&b)
|
569
|
+
}.to yield_with_args(data, nil)
|
570
|
+
end
|
571
|
+
|
572
|
+
context "but #zero_pad? is true" do
|
573
|
+
subject { described_class.new(type, zero_pad: true) }
|
574
|
+
|
575
|
+
it "must yield the zero-padded data and partially decoded int" do
|
576
|
+
expect { |b|
|
577
|
+
subject.each_int(data,&b)
|
578
|
+
}.to yield_with_args("#{data}\x00",0x00030201)
|
579
|
+
end
|
580
|
+
end
|
581
|
+
end
|
582
|
+
end
|
583
|
+
|
584
|
+
context "when the type is big-endian" do
|
585
|
+
let(:type) { Hexdump::TYPES[:int32_be] }
|
586
|
+
let(:raw) { ints.map { |int| [int].pack('l>') } }
|
587
|
+
let(:data) { raw.join }
|
588
|
+
|
589
|
+
subject { described_class.new(type) }
|
590
|
+
|
591
|
+
it "must decode the bytes in big-endian order" do
|
592
|
+
expect { |b|
|
593
|
+
subject.each_int(data,&b)
|
594
|
+
}.to yield_successive_args(*raw.zip(ints))
|
595
|
+
end
|
596
|
+
|
597
|
+
context "but there is not enough bytes to decode a value" do
|
598
|
+
let(:data) { "\x01\x02\x03".encode(Encoding::BINARY) }
|
599
|
+
|
600
|
+
it "must yield the remaining bytes and nil" do
|
601
|
+
expect { |b|
|
602
|
+
subject.each_int(data,&b)
|
603
|
+
}.to yield_with_args(data, nil)
|
604
|
+
end
|
605
|
+
|
606
|
+
context "but #zero_pad? is true" do
|
607
|
+
subject { described_class.new(type, zero_pad: true) }
|
608
|
+
|
609
|
+
it "must yield the zero-padded data and partially decoded int" do
|
610
|
+
expect { |b|
|
611
|
+
subject.each_int(data,&b)
|
612
|
+
}.to yield_with_args("#{data}\x00",0x01020300)
|
613
|
+
end
|
614
|
+
end
|
615
|
+
end
|
616
|
+
end
|
617
|
+
end
|
618
|
+
|
619
|
+
context "when the type has size of 8" do
|
620
|
+
let(:ints) { [0x1122334400aa0001, -0x1122334400bb0002, 0x1122334400cc0003, -0x1122334400dd0004] }
|
621
|
+
|
622
|
+
context "when the type is little-endian" do
|
623
|
+
let(:type) { Hexdump::TYPES[:int64_le] }
|
624
|
+
let(:raw) { ints.map { |int| [int].pack('q<') } }
|
625
|
+
let(:data) { raw.join }
|
626
|
+
|
627
|
+
subject { described_class.new(type) }
|
628
|
+
|
629
|
+
it "must decode the bytes in little-endian order" do
|
630
|
+
expect { |b|
|
631
|
+
subject.each_int(data,&b)
|
632
|
+
}.to yield_successive_args(*raw.zip(ints))
|
633
|
+
end
|
634
|
+
|
635
|
+
context "but there is not enough bytes to decode a value" do
|
636
|
+
let(:data) { "\x01\x02\x03\x04\x05\x06\x07".encode(Encoding::BINARY) }
|
637
|
+
|
638
|
+
it "must yield the remaining bytes and nil" do
|
639
|
+
expect { |b|
|
640
|
+
subject.each_int(data,&b)
|
641
|
+
}.to yield_with_args(data, nil)
|
642
|
+
end
|
643
|
+
|
644
|
+
context "but #zero_pad? is true" do
|
645
|
+
subject { described_class.new(type, zero_pad: true) }
|
646
|
+
|
647
|
+
it "must yield the zero-padded data and partially decoded int" do
|
648
|
+
expect { |b|
|
649
|
+
subject.each_int(data,&b)
|
650
|
+
}.to yield_with_args("#{data}\x00",0x0007060504030201)
|
651
|
+
end
|
652
|
+
end
|
653
|
+
end
|
654
|
+
end
|
655
|
+
|
656
|
+
context "when the type is big-endian" do
|
657
|
+
let(:type) { Hexdump::TYPES[:int64_be] }
|
658
|
+
let(:raw) { ints.map { |int| [int].pack('q>') } }
|
659
|
+
let(:data) { raw.join }
|
660
|
+
|
661
|
+
subject { described_class.new(type) }
|
662
|
+
|
663
|
+
it "must decode the bytes in big-endian order" do
|
664
|
+
expect { |b|
|
665
|
+
subject.each_int(data,&b)
|
666
|
+
}.to yield_successive_args(*raw.zip(ints))
|
667
|
+
end
|
668
|
+
|
669
|
+
context "but there is not enough bytes to decode a value" do
|
670
|
+
let(:data) { "\x01\x02\x03\x04\x05\x06\x07".encode(Encoding::BINARY) }
|
671
|
+
|
672
|
+
it "must yield nil and the remaining bytes" do
|
673
|
+
expect { |b|
|
674
|
+
subject.each_int(data,&b)
|
675
|
+
}.to yield_with_args(data, nil)
|
676
|
+
end
|
677
|
+
|
678
|
+
context "but #zero_pad? is true" do
|
679
|
+
subject { described_class.new(type, zero_pad: true) }
|
680
|
+
|
681
|
+
it "must yield the zero-padded data and partially decoded int" do
|
682
|
+
expect { |b|
|
683
|
+
subject.each_int(data,&b)
|
684
|
+
}.to yield_with_args("#{data}\x00",0x0102030405060700)
|
685
|
+
end
|
686
|
+
end
|
687
|
+
end
|
688
|
+
end
|
689
|
+
end
|
690
|
+
|
691
|
+
context "when the given data does not define #each_byte" do
|
692
|
+
it do
|
693
|
+
expect {
|
694
|
+
subject.each_int(Object.new).to_a
|
695
|
+
}.to raise_error(ArgumentError)
|
696
|
+
end
|
697
|
+
end
|
698
|
+
end
|
699
|
+
|
700
|
+
describe "#each_float" do
|
701
|
+
context "when the type has size of 4" do
|
702
|
+
let(:floats) { [1.0, -3.0, 5.0, -7.0, 9.0] }
|
703
|
+
|
704
|
+
context "when the type is little-endian" do
|
705
|
+
let(:type) { Hexdump::TYPES[:float_le] }
|
706
|
+
let(:raw) { floats.map { |float| [float].pack('e') } }
|
707
|
+
let(:data) { raw.join }
|
708
|
+
|
709
|
+
subject { described_class.new(type) }
|
710
|
+
|
711
|
+
it "must decode the bytes in little-endian order" do
|
712
|
+
expect { |b|
|
713
|
+
subject.each_float(data,&b)
|
714
|
+
}.to yield_successive_args(*raw.zip(floats))
|
715
|
+
end
|
716
|
+
|
717
|
+
context "but there is not enough bytes to decode a value" do
|
718
|
+
let(:data) { "\x01\x02\x03".encode(Encoding::BINARY) }
|
719
|
+
|
720
|
+
it "must yield the remaining bytes and nil" do
|
721
|
+
expect { |b|
|
722
|
+
subject.each_float(data,&b)
|
723
|
+
}.to yield_with_args(data, nil)
|
724
|
+
end
|
725
|
+
|
726
|
+
context "but #zero_pad? is true" do
|
727
|
+
subject { described_class.new(type, zero_pad: true) }
|
728
|
+
|
729
|
+
it "must yield the zero-padded data and partially decoded int" do
|
730
|
+
expect { |b|
|
731
|
+
subject.each_float(data,&b)
|
732
|
+
}.to yield_with_args("#{data}\x00",2.7622535458617227e-40)
|
733
|
+
end
|
734
|
+
end
|
735
|
+
end
|
736
|
+
end
|
737
|
+
|
738
|
+
context "when the type is big-endian" do
|
739
|
+
let(:type) { Hexdump::TYPES[:float_be] }
|
740
|
+
let(:raw) { floats.map { |float| [float].pack('g') } }
|
741
|
+
let(:data) { raw.join }
|
742
|
+
|
743
|
+
subject { described_class.new(type) }
|
744
|
+
|
745
|
+
it "must decode the bytes in big-endian order" do
|
746
|
+
expect { |b|
|
747
|
+
subject.each_float(data,&b)
|
748
|
+
}.to yield_successive_args(*raw.zip(floats))
|
749
|
+
end
|
750
|
+
|
751
|
+
context "but there is not enough bytes to decode a value" do
|
752
|
+
let(:data) { "\x01\x02\x03".encode(Encoding::BINARY) }
|
753
|
+
|
754
|
+
it "must yield the remaining bytes and nil" do
|
755
|
+
expect { |b|
|
756
|
+
subject.each_float(data,&b)
|
757
|
+
}.to yield_with_args(data, nil)
|
758
|
+
end
|
759
|
+
|
760
|
+
context "but #zero_pad? is true" do
|
761
|
+
subject { described_class.new(type, zero_pad: true) }
|
762
|
+
|
763
|
+
it "must yield the zero-padded data and partially decoded int" do
|
764
|
+
expect { |b|
|
765
|
+
subject.each_float(data,&b)
|
766
|
+
}.to yield_with_args("#{data}\x00",2.387938139551892e-38)
|
767
|
+
end
|
768
|
+
end
|
769
|
+
end
|
770
|
+
end
|
771
|
+
end
|
772
|
+
|
773
|
+
context "when the type has size of 8" do
|
774
|
+
let(:floats) { [1.2, -3.4, 5.6, -7.8, 9.0] }
|
775
|
+
|
776
|
+
context "when the type is little-endian" do
|
777
|
+
let(:type) { Hexdump::TYPES[:double_le] }
|
778
|
+
let(:raw) { floats.map { |float| [float].pack('E') } }
|
779
|
+
let(:data) { raw.join }
|
780
|
+
|
781
|
+
subject { described_class.new(type) }
|
782
|
+
|
783
|
+
it "must decode the bytes in little-endian order" do
|
784
|
+
expect { |b|
|
785
|
+
subject.each_float(data,&b)
|
786
|
+
}.to yield_successive_args(*raw.zip(floats))
|
787
|
+
end
|
788
|
+
|
789
|
+
context "but there is not enough bytes to decode a value" do
|
790
|
+
let(:data) { "\x01\x02\x03\x04\x05\x06\x07".encode(Encoding::BINARY) }
|
791
|
+
|
792
|
+
it "must yield the remaining bytes and nil" do
|
793
|
+
expect { |b|
|
794
|
+
subject.each_float(data,&b)
|
795
|
+
}.to yield_with_args(data, nil)
|
796
|
+
end
|
797
|
+
|
798
|
+
context "but #zero_pad? is true" do
|
799
|
+
subject { described_class.new(type, zero_pad: true) }
|
800
|
+
|
801
|
+
it "must yield the zero-padded data and partially decoded int" do
|
802
|
+
expect { |b|
|
803
|
+
subject.each_float(data,&b)
|
804
|
+
}.to yield_with_args("#{data}\x00",9.76739841864353e-309)
|
805
|
+
end
|
806
|
+
end
|
807
|
+
end
|
808
|
+
end
|
809
|
+
|
810
|
+
context "when the type is big-endian" do
|
811
|
+
let(:type) { Hexdump::TYPES[:double_be] }
|
812
|
+
let(:raw) { floats.map { |float| [float].pack('G') } }
|
813
|
+
let(:data) { raw.join }
|
814
|
+
|
815
|
+
subject { described_class.new(type) }
|
816
|
+
|
817
|
+
it "must decode the bytes in big-endian order" do
|
818
|
+
expect { |b|
|
819
|
+
subject.each_float(data,&b)
|
820
|
+
}.to yield_successive_args(*raw.zip(floats))
|
821
|
+
end
|
822
|
+
|
823
|
+
context "but there is not enough bytes to decode a value" do
|
824
|
+
let(:data) { "\x01\x02\x03\x04\x05\x06\x07".encode(Encoding::BINARY) }
|
825
|
+
|
826
|
+
it "must yield the remaining bytes and nil" do
|
827
|
+
expect { |b|
|
828
|
+
subject.each_float(data,&b)
|
829
|
+
}.to yield_with_args(data, nil)
|
830
|
+
end
|
831
|
+
|
832
|
+
context "but #zero_pad? is true" do
|
833
|
+
subject { described_class.new(type, zero_pad: true) }
|
834
|
+
|
835
|
+
it "must yield the zero-padded data and partially decoded int" do
|
836
|
+
expect { |b|
|
837
|
+
subject.each_float(data,&b)
|
838
|
+
}.to yield_with_args("#{data}\x00",8.207880399131826e-304)
|
839
|
+
end
|
840
|
+
end
|
841
|
+
end
|
842
|
+
end
|
843
|
+
end
|
844
|
+
|
845
|
+
context "when the given data does not define #each_byte" do
|
846
|
+
it do
|
847
|
+
expect {
|
848
|
+
subject.each_float(Object.new).to_a
|
849
|
+
}.to raise_error(ArgumentError)
|
850
|
+
end
|
851
|
+
end
|
852
|
+
end
|
853
|
+
|
854
|
+
describe "#each" do
|
855
|
+
context "when the given data does not define #each_byte" do
|
856
|
+
it do
|
857
|
+
expect {
|
858
|
+
subject.each(Object.new).to_a
|
859
|
+
}.to raise_error(ArgumentError)
|
860
|
+
end
|
861
|
+
end
|
862
|
+
end
|
863
|
+
end
|