bindata 1.1.0 → 1.2.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 +7 -0
  2. data/README +32 -1167
  3. data/lib/bindata.rb +3 -3
  4. data/lib/bindata/array.rb +5 -6
  5. data/lib/bindata/base.rb +40 -58
  6. data/lib/bindata/base_primitive.rb +7 -11
  7. data/lib/bindata/bits.rb +47 -44
  8. data/lib/bindata/choice.rb +7 -11
  9. data/lib/bindata/deprecated.rb +17 -2
  10. data/lib/bindata/dsl.rb +332 -0
  11. data/lib/bindata/float.rb +48 -50
  12. data/lib/bindata/int.rb +66 -88
  13. data/lib/bindata/params.rb +112 -59
  14. data/lib/bindata/primitive.rb +8 -88
  15. data/lib/bindata/record.rb +11 -99
  16. data/lib/bindata/registry.rb +16 -3
  17. data/lib/bindata/rest.rb +1 -1
  18. data/lib/bindata/sanitize.rb +71 -53
  19. data/lib/bindata/skip.rb +2 -1
  20. data/lib/bindata/string.rb +3 -3
  21. data/lib/bindata/stringz.rb +1 -1
  22. data/lib/bindata/struct.rb +21 -20
  23. data/lib/bindata/trace.rb +8 -0
  24. data/lib/bindata/wrapper.rb +13 -69
  25. data/manual.haml +2 -2
  26. data/spec/array_spec.rb +1 -1
  27. data/spec/base_primitive_spec.rb +4 -4
  28. data/spec/base_spec.rb +19 -6
  29. data/spec/bits_spec.rb +5 -1
  30. data/spec/choice_spec.rb +13 -2
  31. data/spec/deprecated_spec.rb +31 -0
  32. data/spec/example.rb +5 -1
  33. data/spec/io_spec.rb +2 -4
  34. data/spec/lazy_spec.rb +10 -5
  35. data/spec/primitive_spec.rb +13 -5
  36. data/spec/record_spec.rb +149 -45
  37. data/spec/registry_spec.rb +18 -6
  38. data/spec/spec_common.rb +31 -6
  39. data/spec/string_spec.rb +0 -1
  40. data/spec/stringz_spec.rb +4 -4
  41. data/spec/struct_spec.rb +2 -2
  42. data/spec/system_spec.rb +26 -19
  43. data/spec/wrapper_spec.rb +52 -4
  44. data/tasks/manual.rake +1 -1
  45. data/tasks/pkg.rake +13 -0
  46. metadata +121 -46
  47. data/TODO +0 -3
@@ -6,8 +6,8 @@ require 'bindata/lazy'
6
6
  # A mock data object with customizable fields.
7
7
  class MockDataObject
8
8
  def initialize(methods = {}, params = {}, parent = nil)
9
+ meta = class << self ; self; end
9
10
  methods.each do |k,v|
10
- meta = class << self ; self; end
11
11
  meta.send(:define_method, k.to_sym) { v }
12
12
  end
13
13
  @parameters = params
@@ -15,12 +15,12 @@ class MockDataObject
15
15
  end
16
16
  attr_accessor :parent
17
17
 
18
- def has_parameter?(k)
19
- @parameters.has_key?(k)
18
+ def has_parameter?(key)
19
+ @parameters.has_key?(key)
20
20
  end
21
21
 
22
- def get_parameter(k)
23
- @parameters[k]
22
+ def get_parameter(key)
23
+ @parameters[key]
24
24
  end
25
25
  end
26
26
 
@@ -34,6 +34,11 @@ describe BinData::LazyEvaluator, "with no parents" do
34
34
  @obj = MockDataObject.new(methods, params)
35
35
  end
36
36
 
37
+ it "should evaluate raw value when instantiated" do
38
+ le = LE.new(@obj)
39
+ le.lazy_eval(5).should == 5
40
+ end
41
+
37
42
  it "should evaluate raw value" do
38
43
  LE.eval(@obj, 5).should == 5
39
44
  end
@@ -18,13 +18,15 @@ describe BinData::Primitive, "when subclassing" do
18
18
  end
19
19
  end
20
20
 
21
- describe BinData::Primitive, "when defining" do
21
+ describe BinData::Primitive, "when defining with errors" do
22
22
  it "should fail on non registered types" do
23
23
  lambda {
24
24
  class BadTypePrimitive < BinData::Primitive
25
25
  non_registered_type :a
26
26
  end
27
- }.should raise_error(TypeError)
27
+ }.should raise_error_on_line(TypeError, 2) { |err|
28
+ err.message.should == "unknown type 'non_registered_type' in #{BadTypePrimitive}"
29
+ }
28
30
  end
29
31
 
30
32
  it "should fail on duplicate names" do
@@ -34,7 +36,9 @@ describe BinData::Primitive, "when defining" do
34
36
  int8 :b
35
37
  int8 :a
36
38
  end
37
- }.should raise_error(SyntaxError)
39
+ }.should raise_error_on_line(SyntaxError, 4) { |err|
40
+ err.message.should == "duplicate field 'a' in #{DuplicateNamePrimitive}"
41
+ }
38
42
  end
39
43
 
40
44
  it "should fail when field name shadows an existing method" do
@@ -42,7 +46,9 @@ describe BinData::Primitive, "when defining" do
42
46
  class ExistingNamePrimitive < BinData::Primitive
43
47
  int8 :object_id
44
48
  end
45
- }.should raise_error(NameError)
49
+ }.should raise_error_on_line(NameError, 2) { |err|
50
+ err.message.should == "field 'object_id' shadows an existing method in #{ExistingNamePrimitive}"
51
+ }
46
52
  end
47
53
 
48
54
  it "should fail on unknown endian" do
@@ -50,7 +56,9 @@ describe BinData::Primitive, "when defining" do
50
56
  class BadEndianPrimitive < BinData::Primitive
51
57
  endian 'a bad value'
52
58
  end
53
- }.should raise_error(ArgumentError)
59
+ }.should raise_error_on_line(ArgumentError, 2) { |err|
60
+ err.message.should == "unknown value for endian 'a bad value' in #{BadEndianPrimitive}"
61
+ }
54
62
  end
55
63
  end
56
64
 
@@ -3,71 +3,93 @@
3
3
  require File.expand_path(File.join(File.dirname(__FILE__), "spec_common"))
4
4
  require 'bindata'
5
5
 
6
- def capture_exception(exception_type, &block)
7
- block.call
8
- rescue Exception => err
9
- err.class.should == exception_type
10
- return err
11
- else
12
- lambda {}.should raise_error(exception_type)
13
- end
14
-
15
- describe BinData::Record, "when defining" do
6
+ describe BinData::Record, "when defining with errors" do
16
7
  it "should fail on non registered types" do
17
- err = capture_exception(TypeError) {
8
+ lambda {
18
9
  class BadTypeRecord < BinData::Record
19
10
  non_registered_type :a
20
11
  end
12
+ }.should raise_error_on_line(TypeError, 2) { |err|
13
+ err.message.should == "unknown type 'non_registered_type' in #{BadTypeRecord}"
21
14
  }
22
- err.message.should == "unknown type 'non_registered_type' for #{BadTypeRecord}"
23
15
  end
24
16
 
25
17
  it "should give correct error message for non registered nested types" do
26
- err = capture_exception(TypeError) {
18
+ lambda {
27
19
  class BadNestedTypeRecord < BinData::Record
28
20
  array :a, :type => :non_registered_type
29
21
  end
22
+ }.should raise_error_on_line(TypeError, 2) { |err|
23
+ err.message.should == "unknown type 'non_registered_type' in #{BadNestedTypeRecord}"
24
+ }
25
+ end
26
+
27
+ it "should give correct error message for non registered nested types in blocks" do
28
+ lambda {
29
+ class BadNestedTypeInBlockRecord < BinData::Record
30
+ array :a do
31
+ non_registered_type
32
+ end
33
+ end
34
+ }.should raise_error_on_line(TypeError, 3) { |err|
35
+ err.message.should == "unknown type 'non_registered_type' in #{BinData::Array}"
36
+ }
37
+ end
38
+
39
+ it "should fail on nested choice when missing names" do
40
+ lambda {
41
+ class MissingChoiceNamesRecord < BinData::Record
42
+ choice do
43
+ int8 :a
44
+ int8
45
+ end
46
+ end
47
+ }.should raise_error_on_line(SyntaxError, 4) { |err|
48
+ err.message.should == "fields must either all have names, or none must have names in BinData::Choice"
30
49
  }
31
- err.message.should == "unknown type 'non_registered_type' for #{BadNestedTypeRecord}"
32
50
  end
33
51
 
34
52
  it "should fail on duplicate names" do
35
- err = capture_exception(SyntaxError) {
53
+ lambda {
36
54
  class DuplicateNameRecord < BinData::Record
37
55
  int8 :a
38
56
  int8 :b
39
57
  int8 :a
40
58
  end
59
+ }.should raise_error_on_line(SyntaxError, 4) { |err|
60
+ err.message.should == "duplicate field 'a' in #{DuplicateNameRecord}"
41
61
  }
42
- err.message.should == "duplicate field 'a' in #{DuplicateNameRecord}"
43
62
  end
44
63
 
45
64
  it "should fail on reserved names" do
46
- err = capture_exception(NameError) {
65
+ lambda {
47
66
  class ReservedNameRecord < BinData::Record
48
67
  int8 :a
49
68
  int8 :invert # from Hash.instance_methods
50
69
  end
70
+ }.should raise_error_on_line(NameError, 3) { |err|
71
+ err.message.should == "field 'invert' is a reserved name in #{ReservedNameRecord}"
51
72
  }
52
- err.message.should == "field 'invert' is a reserved name in #{ReservedNameRecord}"
53
73
  end
54
74
 
55
75
  it "should fail when field name shadows an existing method" do
56
- err = capture_exception(NameError) {
76
+ lambda {
57
77
  class ExistingNameRecord < BinData::Record
58
78
  int8 :object_id
59
79
  end
80
+ }.should raise_error_on_line(NameError, 2) { |err|
81
+ err.message.should == "field 'object_id' shadows an existing method in #{ExistingNameRecord}"
60
82
  }
61
- err.message.should == "field 'object_id' shadows an existing method in #{ExistingNameRecord}"
62
83
  end
63
84
 
64
85
  it "should fail on unknown endian" do
65
- err = capture_exception(ArgumentError) {
86
+ lambda {
66
87
  class BadEndianRecord < BinData::Record
67
88
  endian 'a bad value'
68
89
  end
90
+ }.should raise_error_on_line(ArgumentError, 2) { |err|
91
+ err.message.should == "unknown value for endian 'a bad value' in #{BadEndianRecord}"
69
92
  }
70
- err.message.should == "unknown value for endian 'a bad value' in #{BadEndianRecord}"
71
93
  end
72
94
  end
73
95
 
@@ -75,6 +97,7 @@ describe BinData::Record, "with anonymous fields" do
75
97
  class AnonymousRecord < BinData::Record
76
98
  int8 'a', :initial_value => 10
77
99
  int8 ''
100
+ int8
78
101
  int8 :value => :a
79
102
  end
80
103
 
@@ -92,10 +115,10 @@ describe BinData::Record, "with anonymous fields" do
92
115
  end
93
116
 
94
117
  it "should write anonymous fields" do
95
- str = "\001\002\003"
118
+ str = "\001\002\003\004"
96
119
  @obj.read(str)
97
120
  @obj.a.clear
98
- @obj.to_binary_s.should == "\012\002\012"
121
+ @obj.to_binary_s.should == "\012\002\003\012"
99
122
  end
100
123
  end
101
124
 
@@ -195,30 +218,31 @@ describe BinData::Record, "with multiple fields" do
195
218
  end
196
219
 
197
220
  describe BinData::Record, "with nested structs" do
198
- class Inner1Record < BinData::Record
199
- int8 :w, :initial_value => 3
200
- int8 :x, :value => :the_val
201
- end
202
-
203
- class Inner2Record < BinData::Record
204
- int8 :y, :value => lambda { parent.b.w }
205
- int8 :z
206
- end
207
-
208
- class RecordOuter < BinData::Record
209
- int8 :a, :initial_value => 6
210
- inner1_record :b, :the_val => :a
211
- inner2_record :c
221
+ class NestedStructRecord < BinData::Record
222
+ int8 :a, :initial_value => 6
223
+ struct :b, :the_val => :a do
224
+ hide :w
225
+ int8 :w, :initial_value => 3
226
+ int8 :x, :value => :the_val
227
+ end
228
+ struct :c do
229
+ int8 :y, :value => lambda { b.w }
230
+ int8 :z
231
+ end
212
232
  end
213
233
 
214
234
  before(:each) do
215
- @obj = RecordOuter.new
235
+ @obj = NestedStructRecord.new
216
236
  end
217
237
 
218
238
  it "should included nested field names" do
219
239
  @obj.field_names.should == ["a", "b", "c"]
220
240
  end
221
241
 
242
+ it "should hide nested field names" do
243
+ @obj.b.field_names.should == ["x"]
244
+ end
245
+
222
246
  it "should access nested fields" do
223
247
  @obj.a.should == 6
224
248
  @obj.b.w.should == 3
@@ -243,16 +267,97 @@ describe BinData::Record, "with nested structs" do
243
267
  end
244
268
  end
245
269
 
270
+ describe BinData::Record, "with nested array of primitives" do
271
+ class NestedPrimitiveArrayRecord < BinData::Record
272
+ array :a, :initial_length => 3 do
273
+ uint8 :value => lambda { index }
274
+ end
275
+ end
276
+
277
+ before(:each) do
278
+ @obj = NestedPrimitiveArrayRecord.new
279
+ end
280
+
281
+ it "should use block as :type" do
282
+ @obj.snapshot.should == {"a" => [0, 1, 2]}
283
+ end
284
+ end
285
+
286
+ describe BinData::Record, "with nested array of structs" do
287
+ class NestedStructArrayRecord < BinData::Record
288
+ array :a do
289
+ uint8 :b
290
+ uint8 :c
291
+ end
292
+ end
293
+
294
+ before(:each) do
295
+ @obj = NestedStructArrayRecord.new
296
+ end
297
+
298
+ it "should use block as struct for :type" do
299
+ @obj.a[0].b = 2
300
+ @obj.snapshot.should == {"a" => [{"b" => 2, "c" => 0}]}
301
+ end
302
+ end
303
+
304
+ describe BinData::Record, "with nested choice without names" do
305
+ class NestedChoiceRecord < BinData::Record
306
+ choice :a, :selection => 1 do
307
+ uint8 :value => 1
308
+ uint8 :value => 2
309
+ end
310
+ end
311
+
312
+ before(:each) do
313
+ @obj = NestedChoiceRecord.new
314
+ end
315
+
316
+ it "should select choices by index" do
317
+ @obj.a.should == 2
318
+ end
319
+ end
320
+
321
+ describe BinData::Record, "with nested choice with names" do
322
+ class NestedChoiceWithNamesRecord < BinData::Record
323
+ choice :a, :selection => "b" do
324
+ uint8 "b", :value => 1
325
+ uint8 "c", :value => 2
326
+ end
327
+ end
328
+
329
+ before(:each) do
330
+ @obj = NestedChoiceWithNamesRecord.new
331
+ end
332
+
333
+ it "should select choices by name" do
334
+ @obj.a.should == 1
335
+ end
336
+ end
337
+
246
338
  describe BinData::Record, "with an endian defined" do
247
339
  class RecordWithEndian < BinData::Record
248
340
  endian :little
249
341
 
250
342
  uint16 :a
251
343
  float :b
252
- array :c, :type => :int8, :initial_length => 2
253
- choice :d, :choices => [ [:uint16], [:uint32] ], :selection => 1
254
- struct :e, :fields => [ [:uint16, :f], [:uint32be, :g] ]
255
- struct :h, :fields => [ [:struct, :i, {:fields => [[:uint16, :j]]}] ]
344
+ array :c, :initial_length => 2 do
345
+ int8
346
+ end
347
+ choice :d, :selection => 1 do
348
+ uint16
349
+ uint32
350
+ end
351
+ struct :e do
352
+ uint16 :f
353
+ uint32be :g
354
+ end
355
+ struct :h do
356
+ endian :big
357
+ struct :i do
358
+ uint16 :j
359
+ end
360
+ end
256
361
  end
257
362
 
258
363
  before(:each) do
@@ -269,7 +374,7 @@ describe BinData::Record, "with an endian defined" do
269
374
  @obj.e.g = 7
270
375
  @obj.h.i.j = 8
271
376
 
272
- expected = [1, 2.0, 3, 4, 5, 6, 7, 8].pack('veCCVvNv')
377
+ expected = [1, 2.0, 3, 4, 5, 6, 7, 8].pack('veCCVvNn')
273
378
 
274
379
  @obj.to_binary_s.should == expected
275
380
  end
@@ -398,4 +503,3 @@ describe BinData::Record, "derived classes" do
398
503
  child.field_names.should == ["a", "b"]
399
504
  end
400
505
  end
401
-
@@ -23,7 +23,9 @@ describe BinData::Registry do
23
23
  end
24
24
 
25
25
  it "should determine if a name is not registered" do
26
- @r.is_registered?('xyz').should be_false
26
+ lambda {
27
+ @r.is_registered?('xyz')
28
+ }.should raise_error(BinData::UnRegisteredTypeError)
27
29
  end
28
30
 
29
31
  it "should lookup registered names" do
@@ -35,7 +37,9 @@ describe BinData::Registry do
35
37
  end
36
38
 
37
39
  it "should not lookup unregistered names" do
38
- @r.lookup('a_non_existent_sub_class').should be_nil
40
+ lambda {
41
+ @r.lookup('a_non_existent_sub_class')
42
+ }.should raise_error(BinData::UnRegisteredTypeError)
39
43
  end
40
44
 
41
45
  it "should allow overriding of registered classes" do
@@ -71,13 +75,21 @@ describe BinData::Registry, "with numerics" do
71
75
  end
72
76
 
73
77
  it "should not lookup integers without endian" do
74
- @r.lookup("int24").should be_nil
78
+ lambda {
79
+ @r.lookup("int24")
80
+ }.should raise_error(BinData::UnRegisteredTypeError)
75
81
  end
76
82
 
77
83
  it "should not lookup non byte based integers" do
78
- @r.lookup("int3").should be_nil
79
- @r.lookup("int3", :big).should be_nil
80
- @r.lookup("int3", :little).should be_nil
84
+ lambda {
85
+ @r.lookup("int3")
86
+ }.should raise_error(BinData::UnRegisteredTypeError)
87
+ lambda {
88
+ @r.lookup("int3", :big)
89
+ }.should raise_error(BinData::UnRegisteredTypeError)
90
+ lambda {
91
+ @r.lookup("int3", :little)
92
+ }.should raise_error(BinData::UnRegisteredTypeError)
81
93
  end
82
94
 
83
95
  it "should lookup floats with endian" do
@@ -1,11 +1,5 @@
1
1
  $LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(__FILE__), "..", "lib")))
2
2
 
3
- begin
4
- require 'rubygems'
5
- gem 'rspec', '> 1.2.2'
6
- rescue LoadError
7
- end
8
-
9
3
  require 'spec'
10
4
  require 'spec/autorun'
11
5
  require 'stringio'
@@ -20,3 +14,34 @@ class Object
20
14
  cls.send(:public, *protected_method_names)
21
15
  end
22
16
  end
17
+
18
+ class StringIO
19
+ # Returns the value that was written to the io
20
+ def value
21
+ rewind
22
+ read
23
+ end
24
+ end
25
+
26
+ def exception_line(ex)
27
+ idx = ex.backtrace.find_index { |bt| /:in `should'$/ =~ bt }
28
+
29
+ if idx
30
+ line_num_regex = /.*:(\d+)$/
31
+
32
+ err_line = line_num_regex.match(ex.backtrace[0])[1].to_i
33
+ ref_line = line_num_regex.match(ex.backtrace[idx + 1])[1].to_i
34
+
35
+ err_line - ref_line
36
+ else
37
+ raise "Required calling pattern is lambda { xxx }.should raise_error_on_line(...)"
38
+ end
39
+ end
40
+
41
+ def raise_error_on_line(exception, line, &block)
42
+ raise_exception(exception) do |err|
43
+ exception_line(err).should == line
44
+ block.call(err) if block_given?
45
+ end
46
+ end
47
+