bindata 1.5.1 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of bindata might be problematic. Click here for more details.

Files changed (61) hide show
  1. data/ChangeLog.rdoc +7 -0
  2. data/NEWS.rdoc +11 -0
  3. data/Rakefile +6 -1
  4. data/bindata.gemspec +2 -1
  5. data/doc/manual.md +17 -9
  6. data/examples/gzip.rb +2 -2
  7. data/examples/list.rb +2 -2
  8. data/lib/bindata/alignment.rb +4 -9
  9. data/lib/bindata/array.rb +57 -51
  10. data/lib/bindata/base.rb +13 -110
  11. data/lib/bindata/base_primitive.rb +130 -75
  12. data/lib/bindata/bits.rb +5 -7
  13. data/lib/bindata/choice.rb +24 -32
  14. data/lib/bindata/dsl.rb +1 -6
  15. data/lib/bindata/framework.rb +81 -0
  16. data/lib/bindata/int.rb +5 -7
  17. data/lib/bindata/name.rb +28 -0
  18. data/lib/bindata/offset.rb +42 -53
  19. data/lib/bindata/params.rb +33 -38
  20. data/lib/bindata/struct.rb +2 -6
  21. data/lib/bindata/trace.rb +16 -16
  22. data/lib/bindata/version.rb +1 -1
  23. data/lib/bindata/virtual.rb +3 -3
  24. data/{spec/alignment_spec.rb → test/alignment_test.rb} +17 -16
  25. data/test/array_test.rb +371 -0
  26. data/test/base_primitive_test.rb +312 -0
  27. data/test/base_test.rb +183 -0
  28. data/{spec/bits_spec.rb → test/bits_test.rb} +59 -59
  29. data/test/choice_test.rb +260 -0
  30. data/{spec/spec_common.rb → test/common.rb} +33 -18
  31. data/test/count_bytes_remaining_test.rb +41 -0
  32. data/{spec/deprecated_spec.rb → test/deprecated_test.rb} +5 -7
  33. data/test/float_test.rb +72 -0
  34. data/{spec/int_spec.rb → test/int_test.rb} +34 -43
  35. data/{spec/io_spec.rb → test/io_test.rb} +70 -71
  36. data/{spec/lazy_spec.rb → test/lazy_test.rb} +38 -39
  37. data/test/offset_test.rb +93 -0
  38. data/test/params_test.rb +144 -0
  39. data/{spec/primitive_spec.rb → test/primitive_test.rb} +42 -54
  40. data/{spec/record_spec.rb → test/record_test.rb} +133 -154
  41. data/test/registry_test.rb +104 -0
  42. data/test/rest_test.rb +29 -0
  43. data/test/skip_test.rb +28 -0
  44. data/{spec/string_spec.rb → test/string_test.rb} +96 -97
  45. data/test/stringz_test.rb +127 -0
  46. data/{spec/struct_spec.rb → test/struct_test.rb} +119 -120
  47. data/{spec/system_spec.rb → test/system_test.rb} +66 -106
  48. metadata +39 -38
  49. data/lib/a.rb +0 -24
  50. data/spec/array_spec.rb +0 -331
  51. data/spec/base_primitive_spec.rb +0 -238
  52. data/spec/base_spec.rb +0 -376
  53. data/spec/choice_spec.rb +0 -263
  54. data/spec/count_bytes_remaining_spec.rb +0 -38
  55. data/spec/example.rb +0 -21
  56. data/spec/float_spec.rb +0 -37
  57. data/spec/registry_spec.rb +0 -108
  58. data/spec/rest_spec.rb +0 -26
  59. data/spec/skip_spec.rb +0 -27
  60. data/spec/stringz_spec.rb +0 -118
  61. data/tasks/rspec.rake +0 -17
data/test/base_test.rb ADDED
@@ -0,0 +1,183 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path(File.join(File.dirname(__FILE__), "common"))
4
+
5
+ describe "BinData::Base", "framework" do
6
+ class FrameworkBase < BinData::Base
7
+ class << self
8
+ attr_accessor :calls
9
+ def record_calls(&block)
10
+ self.calls = []
11
+ block.call
12
+ end
13
+ end
14
+
15
+ def initialize_instance
16
+ self.class.calls << :initialize_instance
17
+ end
18
+
19
+ def initialize_shared_instance
20
+ self.class.calls << :initialize_shared_instance
21
+ end
22
+
23
+ expose_methods_for_testing
24
+ end
25
+
26
+ let(:obj) do
27
+ FrameworkBase.record_calls { FrameworkBase.new }
28
+ end
29
+
30
+ it "raises errors on unimplemented methods" do
31
+ lambda { obj.clear? }.must_raise NotImplementedError
32
+ lambda { obj.assign(nil) }.must_raise NotImplementedError
33
+ lambda { obj.snapshot }.must_raise NotImplementedError
34
+ lambda { obj.do_read(nil) }.must_raise NotImplementedError
35
+ lambda { obj.do_write(nil) }.must_raise NotImplementedError
36
+ lambda { obj.do_num_bytes }.must_raise NotImplementedError
37
+ end
38
+
39
+ it "calls initialize methods in order" do
40
+ FrameworkBase.record_calls { FrameworkBase.new }
41
+ FrameworkBase.calls.must_equal [:initialize_shared_instance, :initialize_instance]
42
+ end
43
+
44
+ it "does not call #initialize_shared_instance for prototypes" do
45
+ prototype = obj
46
+ FrameworkBase.record_calls { prototype.new }
47
+ FrameworkBase.calls.must_equal [:initialize_instance]
48
+ end
49
+ end
50
+
51
+ describe BinData::Base, "ArgExtractor" do
52
+ class ParamParserBase < BinData::Base
53
+ attr_reader :params
54
+ attr_reader :val
55
+
56
+ def assign(v)
57
+ @val = v
58
+ end
59
+ end
60
+
61
+ it "parses parameters" do
62
+ par = BinData::Base.new
63
+ data = [
64
+ [[3 ], 3, [], nil],
65
+ [[3, par], 3, [], par],
66
+ [[ {:a => 1} ], nil, [:a], nil],
67
+ [[ {:a => 1}, par], nil, [:a], par],
68
+ [[3, {:a => 1} ], 3, [:a], nil],
69
+ [[3, {:a => 1}, par], 3, [:a], par],
70
+ ]
71
+
72
+ data.each do |el|
73
+ args, val, param_keys, parent = *el
74
+ obj = ParamParserBase.new(*args)
75
+ obj.val.must_be_same_as val
76
+ obj.params.keys.must_equal param_keys
77
+ obj.parent.must_be_same_as parent
78
+ end
79
+ end
80
+ end
81
+
82
+ describe BinData::Base do
83
+ class BaseStub < BinData::Base
84
+ # Override to avoid NotImplemented errors
85
+ def clear?; end
86
+ def assign(x); @data = x; end
87
+ def snapshot; @data; end
88
+ def do_read(io) end
89
+ def do_write(io) end
90
+ def do_num_bytes; end
91
+ end
92
+
93
+ let(:obj) { BaseStub.new }
94
+
95
+ it "::bindata_name returns lowercased name" do
96
+ BaseStub.bindata_name.must_equal "base_stub"
97
+ end
98
+
99
+ it "::read instantiates self" do
100
+ BaseStub.read("").must_be_instance_of BaseStub
101
+ end
102
+
103
+ it "#read returns self" do
104
+ obj.read("").must_equal obj
105
+ end
106
+
107
+ it "#write returns self" do
108
+ obj.write("").must_equal obj
109
+ end
110
+
111
+ it "#inspect is forwarded to snapshot" do
112
+ obj.stub :snapshot, [1, 2, 3] do
113
+ obj.inspect.must_equal obj.snapshot.inspect
114
+ end
115
+ end
116
+
117
+ it "#to_s is forwarded to snapshot" do
118
+ obj.stub :snapshot, [1, 2, 3] do
119
+ obj.to_s.must_equal obj.snapshot.to_s
120
+ end
121
+ end
122
+
123
+ it "pretty prints object as snapshot" do
124
+ actual_io = StringIO.new
125
+ expected_io = StringIO.new
126
+
127
+ obj.stub :snapshot, [1, 2, 3] do
128
+ require 'pp'
129
+ PP.pp(obj, actual_io)
130
+ PP.pp(obj.snapshot, expected_io)
131
+ end
132
+
133
+ actual_io.value.must_equal expected_io.value
134
+ end
135
+
136
+ it "#write writes the same as #to_binary_s" do
137
+ class WriteToSBase < BaseStub
138
+ def do_write(io) io.writebytes("abc"); end
139
+ end
140
+
141
+ obj = WriteToSBase.new
142
+ io = StringIO.new
143
+ obj.write(io)
144
+ io.value.must_equal obj.to_binary_s
145
+ end
146
+
147
+ it "#read is forwarded to #do_read" do
148
+ calls = []
149
+ called_clear = lambda { |*a| calls << :clear }
150
+ called_do_read = lambda { |*a| calls << :do_read }
151
+
152
+ obj.stub :clear, called_clear do
153
+ obj.stub :do_read, called_do_read do
154
+ obj.read(nil)
155
+ end
156
+ end
157
+
158
+ calls.must_equal [:clear, :do_read]
159
+ end
160
+
161
+ it "#write is forwarded to #do_write" do
162
+ calls = []
163
+ called_do_write = lambda { |*a| calls << :do_write }
164
+
165
+ obj.stub :do_write, called_do_write do
166
+ obj.write(nil)
167
+ end
168
+
169
+ calls.must_equal [:do_write]
170
+ end
171
+
172
+ it "#num_bytes is forwarded to #do_num_bytes" do
173
+ obj.stub :do_num_bytes, 42 do
174
+ obj.num_bytes.must_equal 42
175
+ end
176
+ end
177
+
178
+ it "#num_bytes rounds up fractional values" do
179
+ obj.stub :do_num_bytes, 42.1 do
180
+ obj.num_bytes.must_equal 43
181
+ end
182
+ end
183
+ end
@@ -1,91 +1,62 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require File.expand_path(File.join(File.dirname(__FILE__), "spec_common"))
4
- require 'bindata/bits'
3
+ require File.expand_path(File.join(File.dirname(__FILE__), "common"))
5
4
 
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
5
+ module AllBitfields
33
6
 
34
- shared_examples "All bitfields" do
35
-
36
- it "have a sensible value of zero" do
7
+ def test_has_a_sensible_value_of_zero
37
8
  all_classes do |bit_class|
38
- bit_class.new.should be_zero
9
+ bit_class.new.must_equal 0
39
10
  end
40
11
  end
41
12
 
42
- it "avoid underflow" do
13
+ def test_avoids_underflow
43
14
  all_classes do |bit_class|
44
- subject = bit_class.new
15
+ obj = bit_class.new
45
16
 
46
- subject.assign(min_value - 1)
47
- subject.should == min_value
17
+ obj.assign(min_value - 1)
18
+ obj.must_equal min_value
48
19
  end
49
20
  end
50
21
 
51
- it "avoid overflow" do
22
+ def test_avoids_overflow
52
23
  all_classes do |bit_class|
53
- subject = bit_class.new
24
+ obj = bit_class.new
54
25
 
55
- subject.assign(max_value + 1)
56
- subject.should == max_value
26
+ obj.assign(max_value + 1)
27
+ obj.must_equal max_value
57
28
  end
58
29
  end
59
30
 
60
- it "assign values" do
31
+ def test_assign_values
61
32
  all_classes do |bit_class|
62
33
  some_values_within_range.each do |val|
63
- subject = bit_class.new
64
- subject.assign(val)
34
+ obj = bit_class.new
35
+ obj.assign(val)
65
36
 
66
- subject.should == val
37
+ obj.must_equal val
67
38
  end
68
39
  end
69
40
  end
70
41
 
71
- it "assign values from other bit objects" do
42
+ def test_assign_values_from_other_bit_objects
72
43
  all_classes do |bit_class|
73
44
  some_values_within_range.each do |val|
74
- subject = bit_class.new
75
- subject.assign(bit_class.new(val))
45
+ obj = bit_class.new
46
+ obj.assign(bit_class.new(val))
76
47
 
77
- subject.should == val
48
+ obj.must_equal val
78
49
  end
79
50
  end
80
51
  end
81
52
 
82
- it "symmetrically #read and #write" do
53
+ def test_symmetrically_read_and_write
83
54
  all_classes do |bit_class|
84
55
  some_values_within_range.each do |val|
85
- subject = bit_class.new
86
- subject.assign(val)
56
+ obj = bit_class.new
57
+ obj.assign(val)
87
58
 
88
- subject.value_read_from_written.should == subject
59
+ obj.value_read_from_written.must_equal obj
89
60
  end
90
61
  end
91
62
  end
@@ -129,9 +100,9 @@ def generate_bit_classes_to_test(endian)
129
100
  end
130
101
 
131
102
  describe "Big endian bitfields" do
132
- include_examples "All bitfields"
103
+ include AllBitfields
133
104
 
134
- before(:all) do
105
+ before do
135
106
  @bits = generate_bit_classes_to_test(:big)
136
107
  end
137
108
 
@@ -140,15 +111,15 @@ describe "Big endian bitfields" do
140
111
  nbytes = (nbits + 7) / 8
141
112
  str = [0b1000_0000].pack("C") + "\000" * (nbytes - 1)
142
113
 
143
- bit_class.read(str).should == 1 << (nbits - 1)
114
+ bit_class.read(str).must_equal 1 << (nbits - 1)
144
115
  end
145
116
  end
146
117
  end
147
118
 
148
119
  describe "Little endian bitfields" do
149
- include_examples "All bitfields"
120
+ include AllBitfields
150
121
 
151
- before(:all) do
122
+ before do
152
123
  @bits = generate_bit_classes_to_test(:little)
153
124
  end
154
125
 
@@ -157,7 +128,36 @@ describe "Little endian bitfields" do
157
128
  nbytes = (nbits + 7) / 8
158
129
  str = [0b0000_0001].pack("C") + "\000" * (nbytes - 1)
159
130
 
160
- bit_class.read(str).should == 1
131
+ bit_class.read(str).must_equal 1
161
132
  end
162
133
  end
163
134
  end
135
+
136
+ describe "Bits of size 1" do
137
+ let(:bit_classes) { [BinData::Bit1, BinData::Bit1le] }
138
+
139
+ it "accept true as value" do
140
+ bit_classes.each do |bit_class|
141
+ obj = bit_class.new
142
+ obj.assign(true)
143
+ obj.must_equal 1
144
+ end
145
+ end
146
+
147
+ it "accept false as value" do
148
+ bit_classes.each do |bit_class|
149
+ obj = bit_class.new
150
+ obj.assign(false)
151
+ obj.must_equal 0
152
+ end
153
+ end
154
+
155
+ it "accept nil as value" do
156
+ bit_classes.each do |bit_class|
157
+ obj = bit_class.new
158
+ obj.assign(nil)
159
+ obj.must_equal 0
160
+ end
161
+ end
162
+ end
163
+
@@ -0,0 +1,260 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path(File.join(File.dirname(__FILE__), "common"))
4
+
5
+ class Chooser
6
+ attr_accessor :choice
7
+ end
8
+
9
+ class BinData::Choice
10
+ def set_chooser(chooser)
11
+ @chooser = chooser
12
+ end
13
+ def choice=(s)
14
+ @chooser.choice = s
15
+ end
16
+ end
17
+
18
+ def create_choice(choices, options = {})
19
+ chooser = Chooser.new
20
+ params = {:choices => choices, :selection => lambda { chooser.choice } }.merge(options)
21
+ choice = BinData::Choice.new(params)
22
+ choice.set_chooser(chooser)
23
+ choice
24
+ end
25
+
26
+ describe BinData::Choice, "when instantiating" do
27
+ it "ensures mandatory parameters are supplied" do
28
+ args = {}
29
+ lambda { BinData::Choice.new(args) }.must_raise ArgumentError
30
+
31
+ args = {:selection => 1}
32
+ lambda { BinData::Choice.new(args) }.must_raise ArgumentError
33
+
34
+ args = {:choices => []}
35
+ lambda { BinData::Choice.new(args) }.must_raise ArgumentError
36
+ end
37
+
38
+ it "fails when a given type is unknown" do
39
+ args = {:choices => [:does_not_exist], :selection => 0}
40
+ lambda { BinData::Choice.new(args) }.must_raise BinData::UnRegisteredTypeError
41
+ end
42
+
43
+ it "fails when a given type is unknown" do
44
+ args = {:choices => {0 => :does_not_exist}, :selection => 0}
45
+ lambda { BinData::Choice.new(args) }.must_raise BinData::UnRegisteredTypeError
46
+ end
47
+
48
+ it "fails when :choices Hash has a symbol as key" do
49
+ args = {:choices => {:a => :example_single}, :selection => 0}
50
+ lambda { BinData::Choice.new(args) }.must_raise ArgumentError
51
+ end
52
+
53
+ it "fails when :choices Hash has a nil key" do
54
+ args = {:choices => {nil => :example_single}, :selection => 0}
55
+ lambda { BinData::Choice.new(args) }.must_raise ArgumentError
56
+ end
57
+ end
58
+
59
+ module ChoiceInitializedWithArrayOrHash
60
+ def test_can_select_the_choice
61
+ obj.choice = 3
62
+ obj.must_equal 30
63
+ end
64
+
65
+ def test_shows_the_current_selection
66
+ obj.choice = 3
67
+ obj.selection.must_equal 3
68
+ end
69
+
70
+ def test_forwards_snapshot
71
+ obj.choice = 3
72
+ obj.snapshot.must_equal 30
73
+ end
74
+
75
+ def test_can_change_the_choice
76
+ obj.choice = 3
77
+
78
+ obj.choice = 7
79
+ obj.must_equal 70
80
+ end
81
+
82
+ def test_fails_if_no_choice_has_been_set
83
+ lambda { obj.to_s }.must_raise IndexError
84
+ end
85
+
86
+ def test_wont_select_an_invalid_choice
87
+ obj.choice = 99
88
+ lambda { obj.to_s }.must_raise IndexError
89
+ end
90
+
91
+ def test_wont_select_a_nil_choice
92
+ obj.choice = 1
93
+ lambda { obj.to_s }.must_raise IndexError
94
+ end
95
+
96
+ def test_handles_missing_methods_correctly
97
+ obj.choice = 3
98
+
99
+ obj.must_respond_to :value
100
+ obj.wont_respond_to :does_not_exist
101
+ lambda { obj.does_not_exist }.must_raise NoMethodError
102
+ end
103
+
104
+ def test_delegates_methods_to_the_selected_single_choice
105
+ obj.choice = 5
106
+ obj.num_bytes.must_equal ExampleSingle.new.num_bytes
107
+ end
108
+ end
109
+
110
+ describe BinData::Choice, "with sparse choices array" do
111
+ include ChoiceInitializedWithArrayOrHash
112
+
113
+ let(:obj) {
114
+ choices = [nil, nil, nil,
115
+ [:example_single, {:value => 30}], nil,
116
+ [:example_single, {:value => 50}], nil,
117
+ [:example_single, {:value => 70}]]
118
+ create_choice(choices)
119
+ }
120
+ end
121
+
122
+ describe BinData::Choice, "with choices hash" do
123
+ include ChoiceInitializedWithArrayOrHash
124
+
125
+ let(:obj) {
126
+ choices = {3 => [:example_single, {:value => 30}],
127
+ 5 => [:example_single, {:value => 50}],
128
+ 7 => [:example_single, {:value => 70}]}
129
+ create_choice(choices)
130
+ }
131
+ end
132
+
133
+ describe BinData::Choice, "with single values" do
134
+ let(:obj) {
135
+ choices = {3 => :example_single,
136
+ 5 => :example_single,
137
+ 7 => :example_single}
138
+ create_choice(choices)
139
+ }
140
+
141
+ it "assigns raw values" do
142
+ obj.choice = 3
143
+ obj.assign(254)
144
+ obj.must_equal 254
145
+ end
146
+
147
+ it "assigns Single values" do
148
+ data = ExampleSingle.new(11)
149
+
150
+ obj.choice = 3
151
+ obj.assign(data)
152
+ obj.must_equal 11
153
+ end
154
+
155
+ it "clears" do
156
+ obj.choice = 3
157
+ obj.assign(254)
158
+
159
+ obj.clear
160
+ obj.must_equal 0
161
+ end
162
+
163
+ it "clears all possible choices" do
164
+ obj.choice = 3
165
+ obj.assign(10)
166
+ obj.choice = 5
167
+ obj.assign(11)
168
+
169
+ obj.clear
170
+
171
+ obj.choice = 3
172
+ obj.must_equal 0
173
+ end
174
+
175
+ it "is clear on initialisation" do
176
+ obj.choice = 3
177
+
178
+ assert obj.clear?
179
+ end
180
+
181
+ it "is not clear after assignment" do
182
+ obj.choice = 3
183
+ obj.assign(254)
184
+
185
+ refute obj.clear?
186
+ end
187
+
188
+ it "does not copy value when changing selection" do
189
+ obj.choice = 3
190
+ obj.assign(254)
191
+
192
+ obj.choice = 7
193
+ obj.wont_equal 254
194
+ end
195
+
196
+ it "behaves as value" do
197
+ obj.choice = 3
198
+ obj.assign(5)
199
+
200
+ (obj + 1).must_equal 6
201
+ (1 + obj).must_equal 6
202
+ end
203
+ end
204
+
205
+ describe BinData::Choice, "with copy_on_change => true" do
206
+ let(:obj) {
207
+ choices = {3 => :example_single,
208
+ 5 => :example_single,
209
+ 7 => :example_single}
210
+ create_choice(choices, :copy_on_change => true)
211
+ }
212
+
213
+ it "copies value when changing selection" do
214
+ obj.choice = 3
215
+ obj.assign(254)
216
+
217
+ obj.choice = 7
218
+ obj.must_equal 254
219
+ end
220
+ end
221
+
222
+ describe BinData::Choice, "with :default" do
223
+ let(:choices) { { "a" => :int8, :default => :int16be } }
224
+
225
+ it "selects for existing case" do
226
+ obj = BinData::Choice.new(:selection => "a", :choices => choices)
227
+ obj.num_bytes.must_equal 1
228
+ end
229
+
230
+ it "selects for default case" do
231
+ obj = BinData::Choice.new(:selection => "other", :choices => choices)
232
+ obj.num_bytes.must_equal 2
233
+ end
234
+ end
235
+
236
+ describe BinData::Choice, "subclassed with default parameters" do
237
+ class DerivedChoice < BinData::Choice
238
+ endian :big
239
+ default_parameter :selection => 'a'
240
+
241
+ uint16 'a'
242
+ uint32 'b'
243
+ uint64 :default
244
+ end
245
+
246
+ it "sets initial selection" do
247
+ obj = DerivedChoice.new
248
+ obj.num_bytes.must_equal 2
249
+ end
250
+
251
+ it "overides default parameter" do
252
+ obj = DerivedChoice.new(:selection => 'b')
253
+ obj.num_bytes.must_equal 4
254
+ end
255
+
256
+ it "selects default selection" do
257
+ obj = DerivedChoice.new(:selection => 'z')
258
+ obj.num_bytes.must_equal 8
259
+ end
260
+ end