bindata 0.9.3 → 0.10.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 (47) hide show
  1. data/ChangeLog +18 -0
  2. data/NEWS +59 -0
  3. data/README +22 -23
  4. data/TODO +18 -12
  5. data/examples/gzip.rb +4 -4
  6. data/lib/bindata.rb +4 -3
  7. data/lib/bindata/array.rb +202 -132
  8. data/lib/bindata/base.rb +147 -166
  9. data/lib/bindata/{single.rb → base_primitive.rb} +82 -56
  10. data/lib/bindata/bits.rb +31 -770
  11. data/lib/bindata/choice.rb +157 -82
  12. data/lib/bindata/float.rb +25 -27
  13. data/lib/bindata/int.rb +144 -177
  14. data/lib/bindata/io.rb +59 -49
  15. data/lib/bindata/lazy.rb +80 -50
  16. data/lib/bindata/params.rb +134 -26
  17. data/lib/bindata/{single_value.rb → primitive.rb} +71 -64
  18. data/lib/bindata/{multi_value.rb → record.rb} +52 -70
  19. data/lib/bindata/registry.rb +49 -17
  20. data/lib/bindata/rest.rb +6 -10
  21. data/lib/bindata/sanitize.rb +55 -70
  22. data/lib/bindata/string.rb +60 -42
  23. data/lib/bindata/stringz.rb +34 -35
  24. data/lib/bindata/struct.rb +197 -152
  25. data/lib/bindata/trace.rb +35 -0
  26. data/spec/array_spec.rb +128 -112
  27. data/spec/{single_spec.rb → base_primitive_spec.rb} +102 -61
  28. data/spec/base_spec.rb +190 -185
  29. data/spec/bits_spec.rb +126 -98
  30. data/spec/choice_spec.rb +89 -98
  31. data/spec/example.rb +19 -0
  32. data/spec/float_spec.rb +28 -44
  33. data/spec/int_spec.rb +217 -127
  34. data/spec/io_spec.rb +41 -24
  35. data/spec/lazy_spec.rb +95 -49
  36. data/spec/primitive_spec.rb +191 -0
  37. data/spec/{multi_value_spec.rb → record_spec.rb} +124 -89
  38. data/spec/registry_spec.rb +53 -12
  39. data/spec/rest_spec.rb +2 -3
  40. data/spec/sanitize_spec.rb +47 -73
  41. data/spec/spec_common.rb +13 -1
  42. data/spec/string_spec.rb +34 -23
  43. data/spec/stringz_spec.rb +10 -18
  44. data/spec/struct_spec.rb +91 -63
  45. data/spec/system_spec.rb +291 -0
  46. metadata +12 -8
  47. data/spec/single_value_spec.rb +0 -131
data/spec/base_spec.rb CHANGED
@@ -4,74 +4,122 @@ require File.expand_path(File.dirname(__FILE__)) + '/spec_common'
4
4
  require 'bindata/base'
5
5
 
6
6
  class BaseStub < BinData::Base
7
+ # Override to avoid NotImplemented errors
7
8
  def clear; end
8
9
  def clear?; end
9
- def single_value?; end
10
- def done_read; end
11
10
  def _do_read(io) end
11
+ def _done_read; end
12
12
  def _do_write(io) end
13
- def _do_num_bytes; end
13
+ def _do_num_bytes(x) end
14
+ def _assign(x); end
14
15
  def _snapshot; end
16
+
17
+ expose_methods_for_testing
18
+ end
19
+
20
+ class MockBaseStub < BaseStub
21
+ attr_accessor :mock
22
+ def clear; mock.clear; end
23
+ def clear?; mock.clear?; end
24
+ def _do_read(io) mock._do_read(io); end
25
+ def _done_read; mock._done_read; end
26
+ def _do_write(io) mock._do_write(io); end
27
+ def _do_num_bytes(x) mock._do_num_bytes(x) end
28
+ def _assign(x); mock._assign(x); end
29
+ def _snapshot; mock._snapshot; end
30
+ end
31
+
32
+ describe BinData::Base, "when subclassing" do
33
+ before(:all) do
34
+ eval <<-END
35
+ class SubClassOfBase < BinData::Base
36
+ expose_methods_for_testing
37
+ end
38
+ END
39
+ end
40
+
41
+ before(:each) do
42
+ @obj = SubClassOfBase.new
43
+ end
44
+
45
+ it "should raise errors on unimplemented methods" do
46
+ lambda { @obj.clear }.should raise_error(NotImplementedError)
47
+ lambda { @obj.clear? }.should raise_error(NotImplementedError)
48
+ lambda { @obj.assign(nil) }.should raise_error(NotImplementedError)
49
+ lambda { @obj.debug_name_of(nil) }.should raise_error(NotImplementedError)
50
+ lambda { @obj.offset_of(nil) }.should raise_error(NotImplementedError)
51
+ lambda { @obj._do_read(nil) }.should raise_error(NotImplementedError)
52
+ lambda { @obj._done_read }.should raise_error(NotImplementedError)
53
+ lambda { @obj._do_write(nil) }.should raise_error(NotImplementedError)
54
+ lambda { @obj._do_num_bytes(nil) }.should raise_error(NotImplementedError)
55
+ lambda { @obj._snapshot }.should raise_error(NotImplementedError)
56
+ end
15
57
  end
16
58
 
17
59
  describe BinData::Base, "with mandatory parameters" do
18
60
  before(:all) do
19
61
  eval <<-END
20
- class MandatoryBase < BinData::Base
21
- bindata_mandatory_parameter :p1
62
+ class MandatoryBase < BaseStub
63
+ mandatory_parameter :p1
64
+ mandatory_parameter :p2
22
65
  end
23
66
  END
24
67
  end
25
68
 
26
- it "should ensure that those parameters are present" do
27
- lambda { MandatoryBase.new(:p1 => "a") }.should_not raise_error
69
+ it "should ensure that all mandatory parameters are present" do
70
+ params = {:p1 => "a", :p2 => "b" }
71
+ lambda { MandatoryBase.new(params) }.should_not raise_error
28
72
  end
29
73
 
30
- it "should fail when those parameters are not present" do
31
- lambda { MandatoryBase.new(:p2 => "a") }.should raise_error(ArgumentError)
74
+ it "should fail if not all mandatory parameters are present" do
75
+ params = {:p1 => "a", :xx => "b" }
76
+ lambda { MandatoryBase.new(params) }.should raise_error(ArgumentError)
77
+ end
78
+
79
+ it "should fail if no mandatory parameters are present" do
80
+ lambda { MandatoryBase.new() }.should raise_error(ArgumentError)
32
81
  end
33
82
  end
34
83
 
35
84
  describe BinData::Base, "with default parameters" do
36
85
  before(:all) do
37
86
  eval <<-END
38
- class DefaultBase < BinData::Base
39
- bindata_default_parameter :p1 => "a"
40
- public :has_param?, :no_eval_param
87
+ class DefaultBase < BaseStub
88
+ default_parameter :p1 => "a"
41
89
  end
42
90
  END
43
91
  end
44
92
 
45
- it "should set default parameters if they are not specified" do
93
+ it "should use default parameters when not specified" do
46
94
  obj = DefaultBase.new
47
- obj.should have_param(:p1)
48
- obj.no_eval_param(:p1).should == "a"
95
+ obj.should have_parameter(:p1)
96
+ obj.eval_parameter(:p1).should == "a"
49
97
  end
50
98
 
51
99
  it "should be able to override default parameters" do
52
100
  obj = DefaultBase.new(:p1 => "b")
53
- obj.should have_param(:p1)
54
- obj.no_eval_param(:p1).should == "b"
101
+ obj.should have_parameter(:p1)
102
+ obj.eval_parameter(:p1).should == "b"
55
103
  end
56
104
  end
57
105
 
58
106
  describe BinData::Base, "with mutually exclusive parameters" do
59
107
  before(:all) do
60
108
  eval <<-END
61
- class MutexParamBase < BinData::Base
62
- bindata_optional_parameters :p1, :p2
63
- bindata_mutually_exclusive_parameters :p1, :p2
109
+ class MutexParamBase < BaseStub
110
+ optional_parameters :p1, :p2
111
+ mutually_exclusive_parameters :p1, :p2
64
112
  end
65
113
  END
66
114
  end
67
115
 
68
- it "should not fail when neither of those parameters is present" do
116
+ it "should not fail when neither of those parameters are present" do
69
117
  lambda { MutexParamBase.new }.should_not raise_error
70
118
  end
71
119
 
72
120
  it "should not fail when only one of those parameters is present" do
73
121
  lambda { MutexParamBase.new(:p1 => "a") }.should_not raise_error
74
- lambda { MutexParamBase.new(:p2 => "a") }.should_not raise_error
122
+ lambda { MutexParamBase.new(:p2 => "b") }.should_not raise_error
75
123
  end
76
124
 
77
125
  it "should fail when both those parameters are present" do
@@ -82,24 +130,46 @@ end
82
130
  describe BinData::Base, "with multiple parameters" do
83
131
  before(:all) do
84
132
  eval <<-END
85
- class WithParamBase < BinData::Base
86
- bindata_mandatory_parameter :p1
87
- bindata_optional_parameter :p2
88
- bindata_default_parameter :p3 => '3'
89
- public :has_param?, :eval_param, :no_eval_param
133
+ class WithParamBase < BaseStub
134
+ mandatory_parameter :p1
135
+ optional_parameter :p2
136
+ default_parameter :p3 => 3
90
137
  end
91
138
  END
92
139
  end
93
140
 
94
- it "should not allow parameters with nil values" do
95
- lambda { WithParamBase.new(:p1 => 1, :p2 => nil) }.should raise_error(ArgumentError)
141
+ it "should identify internally accepted parameters" do
142
+ accepted = WithParamBase.accepted_internal_parameters
143
+ accepted.should include(:p1)
144
+ accepted.should include(:p2)
145
+ accepted.should include(:p3)
146
+ accepted.should_not include(:xx)
147
+ end
148
+
149
+ it "should evaluate parameters" do
150
+ params = {:p1 => 1, :p2 => 2, :p3 => 3, :p4 => lambda { 4 }}
151
+ obj = WithParamBase.new(params)
152
+ obj.eval_parameter(:p4).should == 4
96
153
  end
97
154
 
98
- it "should identify extra parameters" do
99
- obj = WithParamBase.new({:p1 => 1, :p3 => 3, :p4 => 4, :p5 => 5})
100
- obj.parameters.should == {:p4 => 4, :p5 => 5}
155
+ it "should return parameters" do
156
+ params = {:p1 => 1, :p2 => 2, :p3 => 3, :p4 => :a}
157
+ obj = WithParamBase.new(params)
158
+ obj.get_parameter(:p4).should == :a
101
159
  end
102
160
 
161
+ it "should have parameters" do
162
+ params = {:p1 => 1, :p2 => 2, :p3 => 3, :p4 => 4}
163
+ obj = WithParamBase.new(params)
164
+ obj.should have_parameter(:p4)
165
+ end
166
+
167
+ it "should not allow parameters with nil values" do
168
+ lambda { WithParamBase.new(:p1 => 1, :p2 => nil) }.should raise_error(ArgumentError)
169
+ end
170
+
171
+ =begin
172
+ # TODO: how should we evaluate internal parameters? think about this
103
173
  it "should only recall mandatory, default and optional parameters" do
104
174
  obj = WithParamBase.new(:p1 => 1, :p3 => 3, :p4 => 4, :p5 => 5)
105
175
  obj.should have_param(:p1)
@@ -111,26 +181,19 @@ describe BinData::Base, "with multiple parameters" do
111
181
 
112
182
  it "should evaluate mandatory, default and optional parameters" do
113
183
  obj = WithParamBase.new(:p1 => 1, :p3 => lambda {1 + 2}, :p4 => 4, :p5 => 5)
114
- obj.eval_param(:p1).should == 1
115
- obj.eval_param(:p2).should be_nil
116
- obj.eval_param(:p3).should == 3
117
- obj.eval_param(:p4).should be_nil
118
- obj.eval_param(:p5).should be_nil
184
+ obj.eval_parameter(:p1).should == 1
185
+ obj.eval_parameter(:p2).should be_nil
186
+ obj.eval_parameter(:p3).should == 3
187
+ obj.eval_parameter(:p4).should be_nil
188
+ obj.eval_parameter(:p5).should be_nil
119
189
  end
190
+ =end
120
191
 
121
192
  it "should be able to access without evaluating" do
122
193
  obj = WithParamBase.new(:p1 => :asym, :p3 => lambda {1 + 2})
123
- obj.no_eval_param(:p1).should == :asym
124
- obj.no_eval_param(:p2).should be_nil
125
- obj.no_eval_param(:p3).should respond_to(:arity)
126
- end
127
-
128
- it "should identify accepted parameters" do
129
- internal_parameters = WithParamBase.internal_parameters
130
- internal_parameters.should include(:p1)
131
- internal_parameters.should include(:p2)
132
- internal_parameters.should include(:p3)
133
- internal_parameters.should_not include(:p4)
194
+ obj.get_parameter(:p1).should == :asym
195
+ obj.get_parameter(:p2).should be_nil
196
+ obj.get_parameter(:p3).should respond_to(:arity)
134
197
  end
135
198
  end
136
199
 
@@ -147,32 +210,32 @@ describe BinData::Base, "with :check_offset" do
147
210
  END
148
211
  end
149
212
 
213
+ before(:each) do
214
+ @io = StringIO.new("12345678901234567890")
215
+ end
216
+
150
217
  it "should fail if offset is incorrect" do
151
- io = StringIO.new("12345678901234567890")
152
- io.seek(2)
218
+ @io.seek(2)
153
219
  obj = TenByteOffsetBase.new(:check_offset => 8)
154
- lambda { obj.read(io) }.should raise_error(BinData::ValidityError)
220
+ lambda { obj.read(@io) }.should raise_error(BinData::ValidityError)
155
221
  end
156
222
 
157
223
  it "should succeed if offset is correct" do
158
- io = StringIO.new("12345678901234567890")
159
- io.seek(3)
224
+ @io.seek(3)
160
225
  obj = TenByteOffsetBase.new(:check_offset => 10)
161
- lambda { obj.read(io) }.should_not raise_error
226
+ lambda { obj.read(@io) }.should_not raise_error
162
227
  end
163
228
 
164
229
  it "should fail if :check_offset fails" do
165
- io = StringIO.new("12345678901234567890")
166
- io.seek(4)
230
+ @io.seek(4)
167
231
  obj = TenByteOffsetBase.new(:check_offset => lambda { offset == 11 } )
168
- lambda { obj.read(io) }.should raise_error(BinData::ValidityError)
232
+ lambda { obj.read(@io) }.should raise_error(BinData::ValidityError)
169
233
  end
170
234
 
171
235
  it "should succeed if :check_offset succeeds" do
172
- io = StringIO.new("12345678901234567890")
173
- io.seek(5)
236
+ @io.seek(5)
174
237
  obj = TenByteOffsetBase.new(:check_offset => lambda { offset == 10 } )
175
- lambda { obj.read(io) }.should_not raise_error
238
+ lambda { obj.read(@io) }.should_not raise_error
176
239
  end
177
240
  end
178
241
 
@@ -189,175 +252,117 @@ describe BinData::Base, "with :adjust_offset" do
189
252
  END
190
253
  end
191
254
 
255
+ before(:each) do
256
+ @io = StringIO.new("12345678901234567890")
257
+ end
258
+
192
259
  it "should be mutually exclusive with :check_offset" do
193
260
  params = { :check_offset => 8, :adjust_offset => 8 }
194
261
  lambda { TenByteAdjustingOffsetBase.new(params) }.should raise_error(ArgumentError)
195
262
  end
196
263
 
197
264
  it "should adjust if offset is incorrect" do
198
- io = StringIO.new("12345678901234567890")
199
- io.seek(2)
265
+ @io.seek(2)
200
266
  obj = TenByteAdjustingOffsetBase.new(:adjust_offset => 13)
201
- obj.read(io)
202
- io.pos.should == (2 + 13)
267
+ obj.read(@io)
268
+ @io.pos.should == (2 + 13)
203
269
  end
204
270
 
205
271
  it "should succeed if offset is correct" do
206
- io = StringIO.new("12345678901234567890")
207
- io.seek(3)
272
+ @io.seek(3)
208
273
  obj = TenByteAdjustingOffsetBase.new(:adjust_offset => 10)
209
- lambda { obj.read(io) }.should_not raise_error
210
- io.pos.should == (3 + 10)
274
+ lambda { obj.read(@io) }.should_not raise_error
275
+ @io.pos.should == (3 + 10)
211
276
  end
212
277
 
213
278
  it "should fail if cannot adjust offset" do
214
- io = StringIO.new("12345678901234567890")
215
- io.seek(3)
279
+ @io.seek(3)
216
280
  obj = TenByteAdjustingOffsetBase.new(:adjust_offset => -4)
217
- lambda { obj.read(io) }.should raise_error(BinData::ValidityError)
281
+ lambda { obj.read(@io) }.should raise_error(BinData::ValidityError)
218
282
  end
219
283
  end
220
284
 
221
- describe BinData::Base, "with :onlyif => false" do
222
- before(:all) do
223
- eval <<-END
224
- class OnlyIfBase < BaseStub
225
- attr_accessor :mock
226
- def _do_read(io) mock._do_read(io); end
227
- def _do_write(io) mock._do_write(io); end
228
- def _do_num_bytes; mock._do_num_bytes; end
229
- def _snapshot; mock._snapshot; end
230
- end
231
- END
232
- end
233
-
234
- before(:each) do
235
- @obj = OnlyIfBase.new :onlyif => false
236
- @obj.mock = mock('mock')
237
- end
238
-
239
- it "should not read" do
240
- io = StringIO.new("12345678901234567890")
241
- @obj.mock.should_not_receive(:_do_read)
242
- @obj.read(io)
285
+ describe BinData::Base, "as black box" do
286
+ it "should access parent" do
287
+ parent = BaseStub.new
288
+ child = BaseStub.new(nil, parent)
289
+ child.parent.should == parent
243
290
  end
244
291
 
245
- it "should not write" do
246
- io = StringIO.new
247
- @obj.mock.should_not_receive(:_do_write)
248
- @obj.write(io)
292
+ it "should instantiate self for ::read" do
293
+ BaseStub.read("").class.should == BaseStub
249
294
  end
250
295
 
251
- it "should have zero num_bytes" do
252
- @obj.mock.should_not_receive(:_do_num_bytes)
253
- @obj.num_bytes.should be_zero
296
+ it "should return self for #read" do
297
+ obj = BaseStub.new
298
+ obj.read("").should == obj
254
299
  end
255
300
 
256
- it "should have nil snapshot" do
257
- @obj.mock.should_not_receive(:_snapshot)
258
- @obj.snapshot.should be_nil
301
+ it "should return self for #write" do
302
+ obj = BaseStub.new
303
+ obj.write("").should == obj
259
304
  end
260
- end
261
305
 
262
- describe BinData::Base, "with :readwrite" do
263
- before(:all) do
264
- eval <<-END
265
- class NoIOBase < BinData::Base
266
- public :has_param?, :no_eval_param
267
- end
268
- END
306
+ it "should forward #inspect to snapshot" do
307
+ class SnapshotBase < BaseStub
308
+ def snapshot; [1, 2, 3]; end
309
+ end
310
+ obj = SnapshotBase.new
311
+ obj.inspect.should == obj.snapshot.inspect
269
312
  end
270
313
 
271
- it "should alias to :onlyif" do
272
- obj = NoIOBase.new(:readwrite => "a")
273
- obj.should_not have_param(:readwrite)
274
- obj.should have_param(:onlyif)
275
- obj.no_eval_param(:onlyif).should == "a"
314
+ it "should forward #to_s to snapshot" do
315
+ class SnapshotBase < BaseStub
316
+ def snapshot; [1, 2, 3]; end
317
+ end
318
+ obj = SnapshotBase.new
319
+ obj.to_s.should == obj.snapshot.to_s
276
320
  end
277
- end
278
321
 
279
- describe BinData::Base, "when subclassing" do
280
- before(:all) do
281
- eval <<-END
282
- class SubClassOfBase < BinData::Base
283
- public :_do_read, :_do_write, :_do_num_bytes, :_snapshot
284
- end
285
- END
286
- end
322
+ it "should write the same as to_binary_s" do
323
+ class WriteToSBase < BaseStub
324
+ def _do_write(io) io.writebytes("abc"); end
325
+ end
287
326
 
288
- before(:each) do
289
- @obj = SubClassOfBase.new
290
- end
291
-
292
- it "should raise errors on unimplemented methods" do
293
- lambda { @obj.clear }.should raise_error(NotImplementedError)
294
- lambda { @obj.clear? }.should raise_error(NotImplementedError)
295
- lambda { @obj.single_value? }.should raise_error(NotImplementedError)
296
- lambda { @obj.done_read }.should raise_error(NotImplementedError)
297
- lambda { @obj._do_read(nil) }.should raise_error(NotImplementedError)
298
- lambda { @obj._do_write(nil) }.should raise_error(NotImplementedError)
299
- lambda { @obj._do_num_bytes }.should raise_error(NotImplementedError)
300
- lambda { @obj._snapshot }.should raise_error(NotImplementedError)
327
+ obj = WriteToSBase.new
328
+ io = StringIO.new
329
+ obj.write(io)
330
+ io.rewind
331
+ written = io.read
332
+ obj.to_binary_s.should == written
301
333
  end
302
334
  end
303
335
 
304
- describe BinData::Base, "when subclassing as a single value" do
305
- before(:all) do
306
- eval <<-END
307
- class SingleValueSubClassOfBase < BaseStub
308
- def single_value?; true; end
309
- def value; 123; end
310
- end
311
- END
312
- end
313
-
336
+ describe BinData::Base, "as white box" do
314
337
  before(:each) do
315
- @obj = SingleValueSubClassOfBase.new
316
- end
317
-
318
- it "should return value when reading" do
319
- SingleValueSubClassOfBase.read("").should == 123
320
- end
321
- end
322
-
323
- describe BinData::Base, "when subclassing as multi values" do
324
- before(:all) do
325
- eval <<-END
326
- class MultiValueSubClassOfBase < BaseStub
327
- def single_value?; false; end
328
- def value; 123; end
329
- end
330
- END
338
+ @obj = MockBaseStub.new
339
+ @obj.mock = mock('mock')
331
340
  end
332
341
 
333
- it "should return self when reading" do
334
- obj = MultiValueSubClassOfBase.read("")
335
- obj.class.should == MultiValueSubClassOfBase
342
+ it "should forward read to _do_read" do
343
+ @obj.mock.should_receive(:clear).ordered
344
+ @obj.mock.should_receive(:_do_read).ordered
345
+ @obj.mock.should_receive(:_done_read).ordered
346
+ @obj.read(nil)
336
347
  end
337
- end
338
348
 
339
- describe BinData::Base do
340
- before(:all) do
341
- eval <<-END
342
- class InstanceOfBase < BaseStub
343
- def snapshot; 123; end
344
- def _do_write(io); io.writebytes('456'); end
345
- end
346
- END
349
+ it "should forward write to _do_write" do
350
+ @obj.mock.should_receive(:_do_write)
351
+ @obj.write(nil)
347
352
  end
348
353
 
349
- before(:each) do
350
- @obj = InstanceOfBase.new
354
+ it "should forward num_bytes to _do_num_bytes" do
355
+ @obj.mock.should_receive(:_do_num_bytes).and_return(42)
356
+ @obj.num_bytes.should == 42
351
357
  end
352
358
 
353
- it "should forward #inspect to snapshot" do
354
- @obj.inspect.should == 123.inspect
359
+ it "should round up fractional num_bytes" do
360
+ @obj.mock.should_receive(:_do_num_bytes).and_return(42.1)
361
+ @obj.num_bytes.should == 43
355
362
  end
356
363
 
357
- it "should write the same as to_s" do
358
- io = StringIO.new
359
- @obj.write(io)
360
- io.rewind
361
- io.read.should == @obj.to_s
364
+ it "should forward snapshot to _snapshot" do
365
+ @obj.mock.should_receive(:_snapshot).and_return("abc")
366
+ @obj.snapshot.should == "abc"
362
367
  end
363
368
  end