jbangert-bindata 1.5.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.
- data/.gitignore +1 -0
- data/BSDL +22 -0
- data/COPYING +52 -0
- data/ChangeLog.rdoc +204 -0
- data/Gemfile +2 -0
- data/INSTALL +11 -0
- data/NEWS.rdoc +164 -0
- data/README.md +54 -0
- data/Rakefile +13 -0
- data/bindata.gemspec +31 -0
- data/doc/manual.haml +407 -0
- data/doc/manual.md +1649 -0
- data/examples/NBT.txt +149 -0
- data/examples/gzip.rb +161 -0
- data/examples/ip_address.rb +22 -0
- data/examples/list.rb +124 -0
- data/examples/nbt.rb +178 -0
- data/lib/bindata.rb +33 -0
- data/lib/bindata/alignment.rb +83 -0
- data/lib/bindata/array.rb +335 -0
- data/lib/bindata/base.rb +388 -0
- data/lib/bindata/base_primitive.rb +214 -0
- data/lib/bindata/bits.rb +87 -0
- data/lib/bindata/choice.rb +216 -0
- data/lib/bindata/count_bytes_remaining.rb +35 -0
- data/lib/bindata/deprecated.rb +50 -0
- data/lib/bindata/dsl.rb +312 -0
- data/lib/bindata/float.rb +80 -0
- data/lib/bindata/int.rb +184 -0
- data/lib/bindata/io.rb +274 -0
- data/lib/bindata/lazy.rb +105 -0
- data/lib/bindata/offset.rb +91 -0
- data/lib/bindata/params.rb +135 -0
- data/lib/bindata/primitive.rb +135 -0
- data/lib/bindata/record.rb +110 -0
- data/lib/bindata/registry.rb +92 -0
- data/lib/bindata/rest.rb +35 -0
- data/lib/bindata/sanitize.rb +290 -0
- data/lib/bindata/skip.rb +48 -0
- data/lib/bindata/string.rb +145 -0
- data/lib/bindata/stringz.rb +96 -0
- data/lib/bindata/struct.rb +388 -0
- data/lib/bindata/trace.rb +94 -0
- data/lib/bindata/version.rb +3 -0
- data/setup.rb +1585 -0
- data/spec/alignment_spec.rb +61 -0
- data/spec/array_spec.rb +331 -0
- data/spec/base_primitive_spec.rb +238 -0
- data/spec/base_spec.rb +376 -0
- data/spec/bits_spec.rb +163 -0
- data/spec/choice_spec.rb +263 -0
- data/spec/count_bytes_remaining_spec.rb +38 -0
- data/spec/deprecated_spec.rb +31 -0
- data/spec/example.rb +21 -0
- data/spec/float_spec.rb +37 -0
- data/spec/int_spec.rb +216 -0
- data/spec/io_spec.rb +352 -0
- data/spec/lazy_spec.rb +217 -0
- data/spec/primitive_spec.rb +202 -0
- data/spec/record_spec.rb +530 -0
- data/spec/registry_spec.rb +108 -0
- data/spec/rest_spec.rb +26 -0
- data/spec/skip_spec.rb +27 -0
- data/spec/spec_common.rb +58 -0
- data/spec/string_spec.rb +300 -0
- data/spec/stringz_spec.rb +118 -0
- data/spec/struct_spec.rb +350 -0
- data/spec/system_spec.rb +380 -0
- data/tasks/manual.rake +36 -0
- data/tasks/rspec.rake +17 -0
- metadata +208 -0
data/spec/base_spec.rb
ADDED
@@ -0,0 +1,376 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "spec_common"))
|
4
|
+
require 'bindata/base'
|
5
|
+
|
6
|
+
class BaseStub < BinData::Base
|
7
|
+
# Override to avoid NotImplemented errors
|
8
|
+
def clear; end
|
9
|
+
def clear?; end
|
10
|
+
def assign(x); @data = x; end
|
11
|
+
def snapshot; @data; end
|
12
|
+
def do_read(io) end
|
13
|
+
def do_write(io) end
|
14
|
+
def do_num_bytes; end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe BinData::Base, "all subclasses" do
|
18
|
+
class SubClassOfBase < BinData::Base
|
19
|
+
expose_methods_for_testing
|
20
|
+
end
|
21
|
+
|
22
|
+
subject { SubClassOfBase.new }
|
23
|
+
|
24
|
+
it "raises errors on unimplemented methods" do
|
25
|
+
expect { subject.clear }.to raise_error(NotImplementedError)
|
26
|
+
expect { subject.clear? }.to raise_error(NotImplementedError)
|
27
|
+
expect { subject.assign(nil) }.to raise_error(NotImplementedError)
|
28
|
+
expect { subject.snapshot }.to raise_error(NotImplementedError)
|
29
|
+
expect { subject.do_read(nil) }.to raise_error(NotImplementedError)
|
30
|
+
expect { subject.do_write(nil) }.to raise_error(NotImplementedError)
|
31
|
+
expect { subject.do_num_bytes }.to raise_error(NotImplementedError)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe BinData::Base, "with parameters" do
|
36
|
+
it "raises error when parameter name is invalid" do
|
37
|
+
expect {
|
38
|
+
class InvalidParameterNameBase < BinData::Base
|
39
|
+
optional_parameter :eval # i.e. Kernel#eval
|
40
|
+
end
|
41
|
+
}.to raise_error(NameError)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "raises an error when parameter has nil value" do
|
45
|
+
expect { BaseStub.new(:a => nil) }.to raise_error(ArgumentError)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "converts parameter keys to symbols" do
|
49
|
+
subject = BaseStub.new('a' => 3)
|
50
|
+
subject.should have_parameter(:a)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe BinData::Base, "with mandatory parameters" do
|
55
|
+
class MandatoryBase < BaseStub
|
56
|
+
mandatory_parameter :p1
|
57
|
+
mandatory_parameter :p2
|
58
|
+
end
|
59
|
+
|
60
|
+
it "ensures that all mandatory parameters are present" do
|
61
|
+
params = {:p1 => "a", :p2 => "b" }
|
62
|
+
expect { MandatoryBase.new(params) }.not_to raise_error
|
63
|
+
end
|
64
|
+
|
65
|
+
it "fails when only some mandatory parameters are present" do
|
66
|
+
params = {:p1 => "a", :xx => "b" }
|
67
|
+
expect { MandatoryBase.new(params) }.to raise_error(ArgumentError)
|
68
|
+
end
|
69
|
+
|
70
|
+
it "fails when no mandatory parameters are present" do
|
71
|
+
expect { MandatoryBase.new() }.to raise_error(ArgumentError)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe BinData::Base, "with default parameters" do
|
76
|
+
class DefaultBase < BaseStub
|
77
|
+
default_parameter :p1 => "a"
|
78
|
+
end
|
79
|
+
|
80
|
+
it "uses default parameters when not specified" do
|
81
|
+
subject = DefaultBase.new
|
82
|
+
subject.eval_parameter(:p1).should == "a"
|
83
|
+
end
|
84
|
+
|
85
|
+
it "can override default parameters" do
|
86
|
+
subject = DefaultBase.new(:p1 => "b")
|
87
|
+
subject.eval_parameter(:p1).should == "b"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe BinData::Base, "with mutually exclusive parameters" do
|
92
|
+
class MutexParamBase < BaseStub
|
93
|
+
optional_parameters :p1, :p2
|
94
|
+
mutually_exclusive_parameters :p1, :p2
|
95
|
+
end
|
96
|
+
|
97
|
+
it "does not fail when neither of those parameters are present" do
|
98
|
+
expect { MutexParamBase.new }.not_to raise_error
|
99
|
+
end
|
100
|
+
|
101
|
+
it "does not fail when only one of those parameters is present" do
|
102
|
+
expect { MutexParamBase.new(:p1 => "a") }.not_to raise_error
|
103
|
+
expect { MutexParamBase.new(:p2 => "b") }.not_to raise_error
|
104
|
+
end
|
105
|
+
|
106
|
+
it "fails when both those parameters are present" do
|
107
|
+
expect { MutexParamBase.new(:p1 => "a", :p2 => "b") }.to raise_error(ArgumentError)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe BinData::Base, "with multiple parameters" do
|
112
|
+
class WithParamBase < BaseStub
|
113
|
+
mandatory_parameter :p1
|
114
|
+
default_parameter :p2 => 2
|
115
|
+
optional_parameter :p3
|
116
|
+
end
|
117
|
+
|
118
|
+
it "identifies internally accepted parameters" do
|
119
|
+
accepted = WithParamBase.accepted_parameters.all
|
120
|
+
accepted.should include(:p1)
|
121
|
+
accepted.should include(:p2)
|
122
|
+
accepted.should include(:p3)
|
123
|
+
accepted.should_not include(:xx)
|
124
|
+
end
|
125
|
+
|
126
|
+
context "examining parameters" do
|
127
|
+
subject {
|
128
|
+
params = {:p1 => 1, :p3 => :xx, :p4 => lambda { 4 }}
|
129
|
+
WithParamBase.new(params)
|
130
|
+
}
|
131
|
+
|
132
|
+
it "evaluates parameters" do
|
133
|
+
subject.eval_parameter(:p1).should == 1
|
134
|
+
subject.eval_parameter(:p2).should == 2
|
135
|
+
expect { subject.eval_parameter(:p3) }.to raise_error(NoMethodError)
|
136
|
+
subject.eval_parameter(:p4).should == 4
|
137
|
+
end
|
138
|
+
|
139
|
+
it "gets parameters without evaluating" do
|
140
|
+
subject.get_parameter(:p1).should == 1
|
141
|
+
subject.get_parameter(:p2).should == 2
|
142
|
+
subject.get_parameter(:p3).should == :xx
|
143
|
+
subject.get_parameter(:p4).should respond_to(:arity)
|
144
|
+
end
|
145
|
+
|
146
|
+
it "has parameters" do
|
147
|
+
subject.should have_parameter(:p1)
|
148
|
+
subject.should have_parameter(:p2)
|
149
|
+
subject.should have_parameter(:p3)
|
150
|
+
subject.should have_parameter(:p4)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
describe BinData::Base, "when initializing" do
|
156
|
+
class BaseInit < BaseStub
|
157
|
+
class << self
|
158
|
+
attr_accessor :calls
|
159
|
+
def recorded_calls(&block)
|
160
|
+
self.calls = []
|
161
|
+
block.call
|
162
|
+
calls
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def initialize_instance
|
167
|
+
self.class.calls << :initialize_instance
|
168
|
+
end
|
169
|
+
|
170
|
+
def initialize_shared_instance
|
171
|
+
self.class.calls << :initialize_shared_instance
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
it "calls both #initialize_xxx methods" do
|
176
|
+
BaseInit.recorded_calls {
|
177
|
+
BaseInit.new
|
178
|
+
}.should == [:initialize_shared_instance, :initialize_instance]
|
179
|
+
end
|
180
|
+
|
181
|
+
context "as a factory" do
|
182
|
+
subject { BaseInit.new(:check_offset => 1) }
|
183
|
+
|
184
|
+
describe "#new" do
|
185
|
+
it "calls #initialize_instance" do
|
186
|
+
obj = subject
|
187
|
+
|
188
|
+
BaseInit.recorded_calls {
|
189
|
+
obj.new
|
190
|
+
}.should == [:initialize_instance]
|
191
|
+
end
|
192
|
+
|
193
|
+
it "copies parameters" do
|
194
|
+
obj = subject.new
|
195
|
+
obj.eval_parameter(:check_offset).should == 1
|
196
|
+
end
|
197
|
+
|
198
|
+
it "performs action for :check_offset" do
|
199
|
+
obj = subject.new
|
200
|
+
expect {
|
201
|
+
obj.read("abc")
|
202
|
+
}.to raise_error(BinData::ValidityError)
|
203
|
+
end
|
204
|
+
|
205
|
+
it "assigns value" do
|
206
|
+
obj = subject.new(3)
|
207
|
+
obj.snapshot.should == 3
|
208
|
+
end
|
209
|
+
|
210
|
+
it "sets parent" do
|
211
|
+
obj = subject.new(3, "p")
|
212
|
+
obj.parent.should == "p"
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
describe BinData::Base, "as black box" do
|
219
|
+
context "class methods" do
|
220
|
+
it "returns bindata_name" do
|
221
|
+
BaseStub.bindata_name.should == "base_stub"
|
222
|
+
end
|
223
|
+
|
224
|
+
it "instantiates self for ::read" do
|
225
|
+
BaseStub.read("").class.should == BaseStub
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
it "accesses parent" do
|
230
|
+
parent = BaseStub.new
|
231
|
+
child = BaseStub.new(nil, parent)
|
232
|
+
child.parent.should == parent
|
233
|
+
end
|
234
|
+
|
235
|
+
subject { BaseStub.new }
|
236
|
+
|
237
|
+
it "returns self for #read" do
|
238
|
+
subject.read("").should == subject
|
239
|
+
end
|
240
|
+
|
241
|
+
it "returns self for #write" do
|
242
|
+
subject.write("").should == subject
|
243
|
+
end
|
244
|
+
|
245
|
+
it "forwards #inspect to snapshot" do
|
246
|
+
subject.stub(:snapshot).and_return([1, 2, 3])
|
247
|
+
subject.inspect.should == subject.snapshot.inspect
|
248
|
+
end
|
249
|
+
|
250
|
+
it "forwards #to_s to snapshot" do
|
251
|
+
subject.stub(:snapshot).and_return([1, 2, 3])
|
252
|
+
subject.to_s.should == subject.snapshot.to_s
|
253
|
+
end
|
254
|
+
|
255
|
+
it "pretty prints object as snapshot" do
|
256
|
+
subject.stub(:snapshot).and_return([1, 2, 3])
|
257
|
+
actual_io = StringIO.new
|
258
|
+
expected_io = StringIO.new
|
259
|
+
|
260
|
+
require 'pp'
|
261
|
+
PP.pp(subject, actual_io)
|
262
|
+
PP.pp(subject.snapshot, expected_io)
|
263
|
+
|
264
|
+
actual_io.value.should == expected_io.value
|
265
|
+
end
|
266
|
+
|
267
|
+
it "writes the same as to_binary_s" do
|
268
|
+
class WriteToSBase < BaseStub
|
269
|
+
def do_write(io) io.writebytes("abc"); end
|
270
|
+
end
|
271
|
+
|
272
|
+
subject = WriteToSBase.new
|
273
|
+
io = StringIO.new
|
274
|
+
subject.write(io)
|
275
|
+
io.value.should == subject.to_binary_s
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
describe BinData::Base, "as white box" do
|
280
|
+
subject { BaseStub.new }
|
281
|
+
|
282
|
+
it "forwards read to do_read" do
|
283
|
+
subject.should_receive(:clear).ordered
|
284
|
+
subject.should_receive(:do_read).ordered
|
285
|
+
subject.read(nil)
|
286
|
+
end
|
287
|
+
|
288
|
+
it "forwards write to do_write" do
|
289
|
+
subject.should_receive(:do_write)
|
290
|
+
subject.write(nil)
|
291
|
+
end
|
292
|
+
|
293
|
+
it "forwards num_bytes to do_num_bytes" do
|
294
|
+
subject.should_receive(:do_num_bytes).and_return(42)
|
295
|
+
subject.num_bytes.should == 42
|
296
|
+
end
|
297
|
+
|
298
|
+
it "rounds up fractional num_bytes" do
|
299
|
+
subject.should_receive(:do_num_bytes).and_return(42.1)
|
300
|
+
subject.num_bytes.should == 43
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
describe BinData::Base, "checking offsets" do
|
305
|
+
class TenByteOffsetBase < BaseStub
|
306
|
+
def self.create(params)
|
307
|
+
obj = self.new
|
308
|
+
obj.initialize_child(params)
|
309
|
+
obj
|
310
|
+
end
|
311
|
+
|
312
|
+
def initialize_child(params)
|
313
|
+
@child = BaseStub.new(params, self)
|
314
|
+
end
|
315
|
+
|
316
|
+
def do_read(io)
|
317
|
+
io.seekbytes(10)
|
318
|
+
@child.do_read(io)
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
let(:io) { StringIO.new("12345678901234567890") }
|
323
|
+
|
324
|
+
context "with :check_offset" do
|
325
|
+
it "fails when offset is incorrect" do
|
326
|
+
io.seek(2)
|
327
|
+
subject = TenByteOffsetBase.create(:check_offset => 8)
|
328
|
+
expect { subject.read(io) }.to raise_error(BinData::ValidityError)
|
329
|
+
end
|
330
|
+
|
331
|
+
it "succeeds when offset is correct" do
|
332
|
+
io.seek(3)
|
333
|
+
subject = TenByteOffsetBase.create(:check_offset => 10)
|
334
|
+
expect { subject.read(io) }.not_to raise_error
|
335
|
+
end
|
336
|
+
|
337
|
+
it "fails when :check_offset fails" do
|
338
|
+
io.seek(4)
|
339
|
+
subject = TenByteOffsetBase.create(:check_offset => lambda { offset == 11 } )
|
340
|
+
expect { subject.read(io) }.to raise_error(BinData::ValidityError)
|
341
|
+
end
|
342
|
+
|
343
|
+
it "succeeds when :check_offset succeeds" do
|
344
|
+
io.seek(5)
|
345
|
+
subject = TenByteOffsetBase.create(:check_offset => lambda { offset == 10 } )
|
346
|
+
expect { subject.read(io) }.not_to raise_error
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
context "with :adjust_offset" do
|
351
|
+
it "is mutually exclusive with :check_offset" do
|
352
|
+
params = { :check_offset => 8, :adjust_offset => 8 }
|
353
|
+
expect { TenByteOffsetBase.create(params) }.to raise_error(ArgumentError)
|
354
|
+
end
|
355
|
+
|
356
|
+
it "adjust offset when incorrect" do
|
357
|
+
io.seek(2)
|
358
|
+
subject = TenByteOffsetBase.create(:adjust_offset => 13)
|
359
|
+
subject.read(io)
|
360
|
+
io.pos.should == (2 + 13)
|
361
|
+
end
|
362
|
+
|
363
|
+
it "succeeds when offset is correct" do
|
364
|
+
io.seek(3)
|
365
|
+
subject = TenByteOffsetBase.create(:adjust_offset => 10)
|
366
|
+
expect { subject.read(io) }.not_to raise_error
|
367
|
+
io.pos.should == (3 + 10)
|
368
|
+
end
|
369
|
+
|
370
|
+
it "fails if cannot adjust offset" do
|
371
|
+
io.seek(4)
|
372
|
+
subject = TenByteOffsetBase.create(:adjust_offset => -5)
|
373
|
+
expect { subject.read(io) }.to raise_error(BinData::ValidityError)
|
374
|
+
end
|
375
|
+
end
|
376
|
+
end
|
data/spec/bits_spec.rb
ADDED
@@ -0,0 +1,163 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "spec_common"))
|
4
|
+
require 'bindata/bits'
|
5
|
+
|
6
|
+
describe "Bits of size 1" do
|
7
|
+
let(:bit_classes) { [BinData::Bit1, BinData::Bit1le] }
|
8
|
+
|
9
|
+
it "accept true as value" do
|
10
|
+
bit_classes.each do |bit_class|
|
11
|
+
subject = bit_class.new
|
12
|
+
subject.assign(true)
|
13
|
+
subject.should == 1
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it "accept false as value" do
|
18
|
+
bit_classes.each do |bit_class|
|
19
|
+
subject = bit_class.new
|
20
|
+
subject.assign(false)
|
21
|
+
subject.should == 0
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it "accept nil as value" do
|
26
|
+
bit_classes.each do |bit_class|
|
27
|
+
subject = bit_class.new
|
28
|
+
subject.assign(nil)
|
29
|
+
subject.should == 0
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
shared_examples "All bitfields" do
|
35
|
+
|
36
|
+
it "have a sensible value of zero" do
|
37
|
+
all_classes do |bit_class|
|
38
|
+
bit_class.new.should be_zero
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
it "avoid underflow" do
|
43
|
+
all_classes do |bit_class|
|
44
|
+
subject = bit_class.new
|
45
|
+
|
46
|
+
subject.assign(min_value - 1)
|
47
|
+
subject.should == min_value
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
it "avoid overflow" do
|
52
|
+
all_classes do |bit_class|
|
53
|
+
subject = bit_class.new
|
54
|
+
|
55
|
+
subject.assign(max_value + 1)
|
56
|
+
subject.should == max_value
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
it "assign values" do
|
61
|
+
all_classes do |bit_class|
|
62
|
+
some_values_within_range.each do |val|
|
63
|
+
subject = bit_class.new
|
64
|
+
subject.assign(val)
|
65
|
+
|
66
|
+
subject.should == val
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
it "assign values from other bit objects" do
|
72
|
+
all_classes do |bit_class|
|
73
|
+
some_values_within_range.each do |val|
|
74
|
+
subject = bit_class.new
|
75
|
+
subject.assign(bit_class.new(val))
|
76
|
+
|
77
|
+
subject.should == val
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
it "symmetrically #read and #write" do
|
83
|
+
all_classes do |bit_class|
|
84
|
+
some_values_within_range.each do |val|
|
85
|
+
subject = bit_class.new
|
86
|
+
subject.assign(val)
|
87
|
+
|
88
|
+
subject.value_read_from_written.should == subject
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def all_classes(&block)
|
94
|
+
@bits.each_pair do |bit_class, nbits|
|
95
|
+
@nbits = nbits
|
96
|
+
yield bit_class
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def min_value
|
101
|
+
0
|
102
|
+
end
|
103
|
+
|
104
|
+
def max_value
|
105
|
+
(1 << @nbits) - 1
|
106
|
+
end
|
107
|
+
|
108
|
+
def some_values_within_range
|
109
|
+
lo = min_value + 1
|
110
|
+
mid = (min_value + max_value) / 2
|
111
|
+
hi = max_value - 1
|
112
|
+
|
113
|
+
[lo, mid, hi].select { |val| value_within_range?(val) }
|
114
|
+
end
|
115
|
+
|
116
|
+
def value_within_range?(val)
|
117
|
+
(min_value .. max_value).include?(val)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def generate_bit_classes_to_test(endian)
|
122
|
+
bits = {}
|
123
|
+
(1 .. 50).each do |nbits|
|
124
|
+
name = (endian == :big) ? "Bit#{nbits}" : "Bit#{nbits}le"
|
125
|
+
bit_class = BinData.const_get(name)
|
126
|
+
bits[bit_class] = nbits
|
127
|
+
end
|
128
|
+
bits
|
129
|
+
end
|
130
|
+
|
131
|
+
describe "Big endian bitfields" do
|
132
|
+
include_examples "All bitfields"
|
133
|
+
|
134
|
+
before(:all) do
|
135
|
+
@bits = generate_bit_classes_to_test(:big)
|
136
|
+
end
|
137
|
+
|
138
|
+
it "read big endian values" do
|
139
|
+
@bits.each_pair do |bit_class, nbits|
|
140
|
+
nbytes = (nbits + 7) / 8
|
141
|
+
str = [0b1000_0000].pack("C") + "\000" * (nbytes - 1)
|
142
|
+
|
143
|
+
bit_class.read(str).should == 1 << (nbits - 1)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
describe "Little endian bitfields" do
|
149
|
+
include_examples "All bitfields"
|
150
|
+
|
151
|
+
before(:all) do
|
152
|
+
@bits = generate_bit_classes_to_test(:little)
|
153
|
+
end
|
154
|
+
|
155
|
+
it "read little endian values" do
|
156
|
+
@bits.each_pair do |bit_class, nbits|
|
157
|
+
nbytes = (nbits + 7) / 8
|
158
|
+
str = [0b0000_0001].pack("C") + "\000" * (nbytes - 1)
|
159
|
+
|
160
|
+
bit_class.read(str).should == 1
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|