bindata 0.8.1 → 0.9.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.
- data/ChangeLog +11 -2
- data/README +55 -19
- data/TODO +4 -0
- data/examples/gzip.rb +3 -3
- data/lib/bindata.rb +8 -1
- data/lib/bindata/array.rb +58 -26
- data/lib/bindata/base.rb +133 -83
- data/lib/bindata/choice.rb +142 -61
- data/lib/bindata/float.rb +4 -0
- data/lib/bindata/int.rb +14 -0
- data/lib/bindata/lazy.rb +19 -2
- data/lib/bindata/multi_value.rb +144 -0
- data/lib/bindata/registry.rb +13 -8
- data/lib/bindata/rest.rb +41 -0
- data/lib/bindata/sanitize.rb +36 -0
- data/lib/bindata/single.rb +31 -6
- data/lib/bindata/single_value.rb +203 -0
- data/lib/bindata/string.rb +57 -32
- data/lib/bindata/stringz.rb +15 -0
- data/lib/bindata/struct.rb +189 -204
- data/spec/array_spec.rb +66 -42
- data/spec/base_spec.rb +202 -80
- data/spec/choice_spec.rb +172 -51
- data/spec/int_spec.rb +5 -5
- data/spec/lazy_spec.rb +26 -23
- data/spec/multi_value_spec.rb +250 -0
- data/spec/registry_spec.rb +8 -8
- data/spec/rest_spec.rb +30 -0
- data/spec/sanitize_spec.rb +108 -0
- data/spec/single_spec.rb +63 -49
- data/spec/single_value_spec.rb +131 -0
- data/spec/string_spec.rb +47 -47
- data/spec/stringz_spec.rb +29 -29
- data/spec/struct_spec.rb +112 -198
- metadata +58 -57
data/spec/choice_spec.rb
CHANGED
@@ -6,7 +6,11 @@ require 'bindata/int'
|
|
6
6
|
require 'bindata/lazy'
|
7
7
|
require 'bindata/struct'
|
8
8
|
|
9
|
-
|
9
|
+
class Chooser
|
10
|
+
attr_accessor :choice
|
11
|
+
end
|
12
|
+
|
13
|
+
describe BinData::Choice, "when instantiating" do
|
10
14
|
it "should ensure mandatory parameters are supplied" do
|
11
15
|
args = {}
|
12
16
|
lambda { BinData::Choice.new(args) }.should raise_error(ArgumentError)
|
@@ -20,52 +24,81 @@ describe "Instantiating a Choice" do
|
|
20
24
|
args = {:choices => [:does_not_exist], :selection => 0}
|
21
25
|
lambda { BinData::Choice.new(args) }.should raise_error(TypeError)
|
22
26
|
end
|
27
|
+
|
28
|
+
it "should fail if a given type is unknown" do
|
29
|
+
args = {:choices => {0 => :does_not_exist}, :selection => 0}
|
30
|
+
lambda { BinData::Choice.new(args) }.should raise_error(TypeError)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should fail if :choices isn't an Array or Hash" do
|
34
|
+
args = {:choices => :does_not_exist, :selection => 0}
|
35
|
+
lambda { BinData::Choice.new(args) }.should raise_error(ArgumentError)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should fail if :choices Hash has a symbol as key" do
|
39
|
+
args = {:choices => {:a => :int8}, :selection => 0}
|
40
|
+
lambda { BinData::Choice.new(args) }.should raise_error(ArgumentError)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should fail if :choices Hash has a nil key" do
|
44
|
+
args = {:choices => {nil => :int8}, :selection => 0}
|
45
|
+
lambda { BinData::Choice.new(args) }.should raise_error(ArgumentError)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should fail on all_possible_field_names with unsanitized parameters" do
|
49
|
+
lambda {
|
50
|
+
BinData::Choice.all_possible_field_names({})
|
51
|
+
}.should raise_error(ArgumentError)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should return all possible field names for :choices Hash" do
|
55
|
+
choices = {0 => [:struct, {:fields => [[:int8, :a], [:int8, :b]]}],
|
56
|
+
1 => [:struct, {:fields => [[:int8, :c]]}]}
|
57
|
+
args = {:choices => choices, :selection => 0}
|
58
|
+
params = BinData::SanitizedParameters.new(BinData::Choice, args)
|
59
|
+
BinData::Choice.all_possible_field_names(params).should == ["a", "b", "c"]
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should return all possible field names for :choices Array" do
|
63
|
+
choices = [[:struct, {:fields => [[:int8, :a], [:int8, :b]]}],
|
64
|
+
[:struct, {:fields => [[:int8, :c]]}]]
|
65
|
+
args = {:choices => choices, :selection => 0}
|
66
|
+
params = BinData::SanitizedParameters.new(BinData::Choice, args)
|
67
|
+
BinData::Choice.all_possible_field_names(params).should == ["a", "b", "c"]
|
68
|
+
end
|
23
69
|
end
|
24
70
|
|
25
|
-
describe
|
71
|
+
describe BinData::Choice, "with choices array" do
|
26
72
|
before(:each) do
|
27
|
-
|
28
|
-
@
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
:int8,
|
34
|
-
[:struct,
|
35
|
-
{:fields =>[[:int8, :a]]}],
|
36
|
-
[:int8, {:initial_value => 7}]],
|
37
|
-
:selection => :choose},
|
38
|
-
@env)
|
73
|
+
chooser = Chooser.new
|
74
|
+
@data = BinData::Choice.new(:choices => [[:int8, {:value => 3}],
|
75
|
+
[:int16le, {:value => 5}],
|
76
|
+
[:int32le, {:value => 7}]],
|
77
|
+
:selection => lambda { chooser.choice } )
|
78
|
+
@chooser = chooser
|
39
79
|
end
|
40
80
|
|
41
81
|
it "should be able to select the choice" do
|
42
|
-
@
|
43
|
-
@data.value.should
|
44
|
-
@
|
45
|
-
@data.value.should
|
46
|
-
@
|
47
|
-
@data.value.should
|
48
|
-
@env.choose = 3
|
49
|
-
@data.a.should eql(0)
|
50
|
-
@env.choose = 4
|
51
|
-
@data.value.should eql(7)
|
82
|
+
@chooser.choice = 0
|
83
|
+
@data.value.should == 3
|
84
|
+
@chooser.choice = 1
|
85
|
+
@data.value.should == 5
|
86
|
+
@chooser.choice = 2
|
87
|
+
@data.value.should == 7
|
52
88
|
end
|
53
89
|
|
54
|
-
it "should
|
55
|
-
@
|
56
|
-
lambda { @data.value }.should raise_error(IndexError)
|
57
|
-
@env.choose = 5
|
90
|
+
it "should handle :selection returning nil" do
|
91
|
+
@chooser.choice = nil
|
58
92
|
lambda { @data.value }.should raise_error(IndexError)
|
59
93
|
end
|
60
94
|
|
61
|
-
it "should be able to
|
62
|
-
@
|
63
|
-
@data.value
|
64
|
-
@data.value.should eql(17)
|
95
|
+
it "should not be able to select an invalid choice" do
|
96
|
+
@chooser.choice = 99
|
97
|
+
lambda { @data.value }.should raise_error(IndexError)
|
65
98
|
end
|
66
99
|
|
67
100
|
it "should handle missing methods correctly" do
|
68
|
-
@
|
101
|
+
@chooser.choice = 0
|
69
102
|
|
70
103
|
@data.should respond_to(:value)
|
71
104
|
@data.should_not respond_to(:does_not_exist)
|
@@ -73,33 +106,121 @@ describe "A Choice with several choices" do
|
|
73
106
|
end
|
74
107
|
|
75
108
|
it "should delegate methods to the selected single choice" do
|
76
|
-
@
|
77
|
-
@data.value = 17
|
109
|
+
@chooser.choice = 1
|
78
110
|
|
79
111
|
@data.find_obj_for_name("does_not_exist").should be_nil
|
80
|
-
@data.num_bytes.should
|
112
|
+
@data.num_bytes.should == 2
|
81
113
|
@data.field_names.should be_empty
|
82
|
-
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
describe BinData::Choice, "with sparse choices array" do
|
118
|
+
before(:each) do
|
119
|
+
chooser = Chooser.new
|
120
|
+
@data = BinData::Choice.new(:choices => [nil, nil, nil,
|
121
|
+
[:int8, {:value => 3}],
|
122
|
+
nil,
|
123
|
+
[:int16le, {:value => 5}],
|
124
|
+
nil,
|
125
|
+
[:int32le, {:value => 7}]],
|
126
|
+
:selection => lambda { chooser.choice } )
|
127
|
+
@chooser = chooser
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should be able to select the choice" do
|
131
|
+
@chooser.choice = 3
|
132
|
+
@data.value.should == 3
|
133
|
+
@chooser.choice = 7
|
134
|
+
@data.value.should == 7
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should not be able to select an invalid choice" do
|
138
|
+
@chooser.choice = 99
|
139
|
+
lambda { @data.value }.should raise_error(IndexError)
|
140
|
+
end
|
141
|
+
|
142
|
+
it "should not be able to select a nil choice" do
|
143
|
+
@chooser.choice = 1
|
144
|
+
lambda { @data.value }.should raise_error(IndexError)
|
145
|
+
end
|
146
|
+
end
|
83
147
|
|
84
|
-
|
85
|
-
|
148
|
+
describe BinData::Choice, "with choices hash" do
|
149
|
+
before(:each) do
|
150
|
+
chooser = Chooser.new
|
151
|
+
@data = BinData::Choice.new(:choices => {3 => [:int8, {:value => 3}],
|
152
|
+
5 => [:int16le, {:value => 5}],
|
153
|
+
7 => [:int32le, {:value => 7}]},
|
154
|
+
:selection => lambda { chooser.choice } )
|
155
|
+
@chooser = chooser
|
156
|
+
end
|
86
157
|
|
87
|
-
|
88
|
-
@
|
89
|
-
@data.value.should
|
158
|
+
it "should be able to select the choice" do
|
159
|
+
@chooser.choice = 3
|
160
|
+
@data.value.should == 3
|
161
|
+
@chooser.choice = 7
|
162
|
+
@data.value.should == 7
|
163
|
+
end
|
90
164
|
|
91
|
-
|
92
|
-
@
|
93
|
-
@data.value.should
|
165
|
+
it "should not be able to select an invalid choice" do
|
166
|
+
@chooser.choice = 99
|
167
|
+
lambda { @data.value }.should raise_error(IndexError)
|
168
|
+
end
|
169
|
+
end
|
94
170
|
|
95
|
-
|
171
|
+
describe BinData::Choice, "with single values" do
|
172
|
+
before(:each) do
|
173
|
+
chooser = Chooser.new
|
174
|
+
@data = BinData::Choice.new(:choices => {3 => :uint8,
|
175
|
+
5 => :uint16le,
|
176
|
+
7 => :uint32le,},
|
177
|
+
:selection => lambda { chooser.choice } )
|
178
|
+
@chooser = chooser
|
96
179
|
end
|
97
180
|
|
98
|
-
it "should
|
99
|
-
@
|
100
|
-
@data.
|
101
|
-
|
102
|
-
@data.
|
181
|
+
it "should copy value when changing selection" do
|
182
|
+
@chooser.choice = 3
|
183
|
+
@data.value = 254
|
184
|
+
|
185
|
+
@data.to_s.should == "\xfe"
|
186
|
+
|
187
|
+
@chooser.choice = 5
|
188
|
+
@data.to_s.should == "\xfe\x00"
|
189
|
+
|
190
|
+
@chooser.choice = 7
|
191
|
+
@data.to_s.should == "\xfe\x00\x00\x00"
|
103
192
|
end
|
104
193
|
end
|
105
194
|
|
195
|
+
describe BinData::Choice, "with multi values" do
|
196
|
+
before(:each) do
|
197
|
+
chooser = Chooser.new
|
198
|
+
@data = BinData::Choice.new(:choices =>
|
199
|
+
{3 => [:struct, {:fields => [[:int8, :a]]}],
|
200
|
+
5 => [:struct, {:fields => [[:int8, :a]]}]},
|
201
|
+
:selection => lambda { chooser.choice } )
|
202
|
+
@chooser = chooser
|
203
|
+
end
|
204
|
+
|
205
|
+
it "should access fields" do
|
206
|
+
@chooser.choice = 3
|
207
|
+
@data.a = 5
|
208
|
+
@data.a.should == 5
|
209
|
+
end
|
210
|
+
|
211
|
+
it "should not copy values when changing fields" do
|
212
|
+
@chooser.choice = 3
|
213
|
+
@data.a = 5
|
214
|
+
@data.a.should == 5
|
215
|
+
|
216
|
+
@chooser.choice = 5
|
217
|
+
@data.a = 17
|
218
|
+
@data.a.should == 17
|
219
|
+
|
220
|
+
@chooser.choice = 3
|
221
|
+
@data.a.should == 5
|
222
|
+
|
223
|
+
@chooser.choice = 5
|
224
|
+
@data.a.should == 17
|
225
|
+
end
|
226
|
+
end
|
data/spec/int_spec.rb
CHANGED
@@ -12,7 +12,7 @@ describe "All signed integers" do
|
|
12
12
|
BinData::Int32be,
|
13
13
|
BinData::Int64le,
|
14
14
|
BinData::Int64be].each do |klass|
|
15
|
-
klass.new.value.should
|
15
|
+
klass.new.value.should be_zero
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
@@ -42,7 +42,7 @@ describe "All unsigned integers" do
|
|
42
42
|
BinData::Uint32be,
|
43
43
|
BinData::Uint64le,
|
44
44
|
BinData::Uint64be].each do |klass|
|
45
|
-
klass.new.value.should
|
45
|
+
klass.new.value.should be_zero
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
@@ -68,7 +68,7 @@ def test_read_write(klass, val, clamped_val, str)
|
|
68
68
|
# set the data and ensure clamping occurs
|
69
69
|
data = klass.new
|
70
70
|
data.value = val
|
71
|
-
data.value.should
|
71
|
+
data.value.should == clamped_val
|
72
72
|
|
73
73
|
# write the data
|
74
74
|
io = StringIO.new
|
@@ -76,13 +76,13 @@ def test_read_write(klass, val, clamped_val, str)
|
|
76
76
|
|
77
77
|
# check that we write the expected byte pattern
|
78
78
|
io.rewind
|
79
|
-
io.read.should
|
79
|
+
io.read.should == str
|
80
80
|
|
81
81
|
# check that we read in the same data that was written
|
82
82
|
io.rewind
|
83
83
|
data = klass.new
|
84
84
|
data.read(io)
|
85
|
-
data.value.should
|
85
|
+
data.value.should == clamped_val
|
86
86
|
end
|
87
87
|
|
88
88
|
# return test data for testing unsigned ints
|
data/spec/lazy_spec.rb
CHANGED
@@ -12,31 +12,34 @@ class MockDataObject
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
-
describe
|
15
|
+
describe BinData::LazyEvalEnv do
|
16
16
|
before(:each) do
|
17
17
|
@do1 = MockDataObject.new(:f1 => 'f1')
|
18
18
|
@e1 = BinData::LazyEvalEnv.new
|
19
19
|
@e1.data_object = @do1
|
20
20
|
@e1.add_variable(:v1, 'v1')
|
21
|
+
@e1.add_variable(:v2, 'v2')
|
21
22
|
end
|
22
23
|
|
23
24
|
it "should accept symbols as a shortcut to lambda" do
|
24
|
-
@e1.lazy_eval(lambda { o1 }, :o1 => 'o1').should
|
25
|
-
@e1.lazy_eval(lambda { v1 }).should
|
26
|
-
@e1.lazy_eval(:o1, :o1 => 'o1').should
|
27
|
-
@e1.lazy_eval(:v1).should
|
25
|
+
@e1.lazy_eval(lambda { o1 }, :o1 => 'o1').should == 'o1'
|
26
|
+
@e1.lazy_eval(lambda { v1 }).should == 'v1'
|
27
|
+
@e1.lazy_eval(:o1, :o1 => 'o1').should == 'o1'
|
28
|
+
@e1.lazy_eval(:v1).should == 'v1'
|
29
|
+
@e1.lazy_eval(:v2).should == 'v2'
|
28
30
|
end
|
29
31
|
|
30
32
|
it "should evaluate overrides" do
|
31
|
-
@e1.lazy_eval(:o1, :o1 => 'o1').should
|
33
|
+
@e1.lazy_eval(:o1, :o1 => 'o1').should == 'o1'
|
32
34
|
end
|
33
35
|
|
34
36
|
it "should evaluate variables" do
|
35
|
-
@e1.lazy_eval(:v1).should
|
37
|
+
@e1.lazy_eval(:v1).should == 'v1'
|
38
|
+
@e1.lazy_eval(:v2).should == 'v2'
|
36
39
|
end
|
37
40
|
|
38
41
|
it "should prioritise overrides over variables" do
|
39
|
-
@e1.lazy_eval(:v1, :v1 => 'o1').should
|
42
|
+
@e1.lazy_eval(:v1, :v1 => 'o1').should == 'o1'
|
40
43
|
end
|
41
44
|
|
42
45
|
it "should not resolve any unknown fields" do
|
@@ -46,7 +49,7 @@ describe "A single environment" do
|
|
46
49
|
end
|
47
50
|
end
|
48
51
|
|
49
|
-
describe "
|
52
|
+
describe BinData::LazyEvalEnv, "with one parent" do
|
50
53
|
before(:each) do
|
51
54
|
@do2 = MockDataObject.new(:f2 => 'f2', :common1 => 'f2', :common2 => 'f2')
|
52
55
|
@do1 = MockDataObject.new
|
@@ -64,23 +67,23 @@ describe "An environment with one parent" do
|
|
64
67
|
end
|
65
68
|
|
66
69
|
it "should evaluate parent parameter" do
|
67
|
-
@e1.lazy_eval(:p2).should
|
70
|
+
@e1.lazy_eval(:p2).should == 'p2'
|
68
71
|
end
|
69
72
|
|
70
73
|
it "should evaluate parent field" do
|
71
|
-
@e1.lazy_eval(:f2).should
|
74
|
+
@e1.lazy_eval(:f2).should == 'f2'
|
72
75
|
end
|
73
76
|
|
74
77
|
it "should prefer parent param over parent field" do
|
75
|
-
@e1.lazy_eval(:common1).should
|
78
|
+
@e1.lazy_eval(:common1).should == 'p2'
|
76
79
|
end
|
77
80
|
|
78
81
|
it "should prefer variable over parent param" do
|
79
|
-
@e1.lazy_eval(:common2).should
|
82
|
+
@e1.lazy_eval(:common2).should == 'v1'
|
80
83
|
end
|
81
84
|
end
|
82
85
|
|
83
|
-
describe "
|
86
|
+
describe BinData::LazyEvalEnv, "when nested" do
|
84
87
|
before(:each) do
|
85
88
|
@do4 = MockDataObject.new(:f4 => 'f4')
|
86
89
|
@do3 = MockDataObject.new(:f3 => 'f3')
|
@@ -105,20 +108,20 @@ describe "A nested environment" do
|
|
105
108
|
end
|
106
109
|
|
107
110
|
it "should access parent environments" do
|
108
|
-
@e1.lazy_eval(lambda { parent.p3 }).should
|
109
|
-
@e1.lazy_eval(lambda { parent.parent.p4 }).should
|
111
|
+
@e1.lazy_eval(lambda { parent.p3 }).should == 'p3'
|
112
|
+
@e1.lazy_eval(lambda { parent.parent.p4 }).should == 'p4'
|
110
113
|
end
|
111
114
|
|
112
115
|
it "should cascade lambdas" do
|
113
|
-
@e1.lazy_eval(lambda { l2 }).should
|
114
|
-
@e1.lazy_eval(lambda { s2 }).should
|
116
|
+
@e1.lazy_eval(lambda { l2 }).should == 'l4'
|
117
|
+
@e1.lazy_eval(lambda { s2 }).should == 's4'
|
115
118
|
end
|
116
119
|
|
117
120
|
it "should access parent environments by cascading" do
|
118
|
-
@e1.lazy_eval(lambda { p3 }).should
|
119
|
-
@e1.lazy_eval(lambda { p4 }).should
|
120
|
-
@e1.lazy_eval(lambda { v2 }).should
|
121
|
-
@e1.lazy_eval(lambda { s3 }).should
|
122
|
-
@e1.lazy_eval(lambda { fs2 }).should
|
121
|
+
@e1.lazy_eval(lambda { p3 }).should == 'p3'
|
122
|
+
@e1.lazy_eval(lambda { p4 }).should == 'p4'
|
123
|
+
@e1.lazy_eval(lambda { v2 }).should == 'v2'
|
124
|
+
@e1.lazy_eval(lambda { s3 }).should == 's4'
|
125
|
+
@e1.lazy_eval(lambda { fs2 }).should == 's4'
|
123
126
|
end
|
124
127
|
end
|
@@ -0,0 +1,250 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require File.expand_path(File.dirname(__FILE__)) + '/spec_common'
|
4
|
+
require 'bindata'
|
5
|
+
|
6
|
+
describe BinData::MultiValue, "with hidden fields" do
|
7
|
+
before(:all) do
|
8
|
+
eval <<-END
|
9
|
+
class HiddenMultiValue < BinData::MultiValue
|
10
|
+
hide :b, 'c'
|
11
|
+
int8 :a
|
12
|
+
int8 'b', :initial_value => 10
|
13
|
+
int8 :c
|
14
|
+
int8 :d, :value => :b
|
15
|
+
end
|
16
|
+
END
|
17
|
+
end
|
18
|
+
|
19
|
+
before(:each) do
|
20
|
+
@obj = HiddenMultiValue.new
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should only show fields that aren't hidden" do
|
24
|
+
@obj.field_names.should == ["a", "d"]
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should be able to access hidden fields directly" do
|
28
|
+
@obj.b.should == 10
|
29
|
+
@obj.c = 15
|
30
|
+
@obj.c.should == 15
|
31
|
+
|
32
|
+
@obj.should respond_to(:b=)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should not include hidden fields in snapshot" do
|
36
|
+
@obj.b = 5
|
37
|
+
@obj.snapshot.should == {"a" => 0, "d" => 5}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe BinData::MultiValue, "when defining" do
|
42
|
+
it "should fail on non registered types" do
|
43
|
+
lambda {
|
44
|
+
eval <<-END
|
45
|
+
class BadTypeMultiValue < BinData::MultiValue
|
46
|
+
non_registerd_type :a
|
47
|
+
end
|
48
|
+
END
|
49
|
+
}.should raise_error(TypeError)
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should fail on duplicate names" do
|
53
|
+
lambda {
|
54
|
+
eval <<-END
|
55
|
+
class DuplicateNameMultiValue < BinData::MultiValue
|
56
|
+
int8 :a
|
57
|
+
int8 :b
|
58
|
+
int8 :a
|
59
|
+
end
|
60
|
+
END
|
61
|
+
}.should raise_error(SyntaxError)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should fail on reserved names" do
|
65
|
+
lambda {
|
66
|
+
eval <<-END
|
67
|
+
class ReservedNameMultiValue < BinData::MultiValue
|
68
|
+
int8 :a
|
69
|
+
int8 :invert # from Hash.instance_methods
|
70
|
+
end
|
71
|
+
END
|
72
|
+
}.should raise_error(NameError)
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should fail when field name shadows an existing method" do
|
76
|
+
lambda {
|
77
|
+
eval <<-END
|
78
|
+
class ExistingNameMultiValue < BinData::MultiValue
|
79
|
+
int8 :object_id
|
80
|
+
end
|
81
|
+
END
|
82
|
+
}.should raise_error(NameError)
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should fail on unknown endian" do
|
86
|
+
lambda {
|
87
|
+
eval <<-END
|
88
|
+
class BadEndianMultiValue < BinData::MultiValue
|
89
|
+
endian 'a bad value'
|
90
|
+
end
|
91
|
+
END
|
92
|
+
}.should raise_error(ArgumentError)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe BinData::MultiValue, "with multiple fields" do
|
97
|
+
before(:all) do
|
98
|
+
eval <<-END
|
99
|
+
class MultiFieldMultiValue < BinData::MultiValue
|
100
|
+
int8 :a
|
101
|
+
int8 :b
|
102
|
+
end
|
103
|
+
END
|
104
|
+
end
|
105
|
+
|
106
|
+
before(:each) do
|
107
|
+
@obj = MultiFieldMultiValue.new
|
108
|
+
@obj.a = 1
|
109
|
+
@obj.b = 2
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should return num_bytes" do
|
113
|
+
@obj.num_bytes(:a).should == 1
|
114
|
+
@obj.num_bytes(:b).should == 1
|
115
|
+
@obj.num_bytes.should == 2
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should identify accepted parameters" do
|
119
|
+
BinData::MultiValue.accepted_parameters.should include(:hide)
|
120
|
+
BinData::MultiValue.accepted_parameters.should include(:endian)
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should clear" do
|
124
|
+
@obj.a = 6
|
125
|
+
@obj.clear
|
126
|
+
@obj.clear?.should be_true
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should clear individual elements" do
|
130
|
+
@obj.a = 6
|
131
|
+
@obj.b = 7
|
132
|
+
@obj.clear(:a)
|
133
|
+
@obj.clear?(:a).should be_true
|
134
|
+
@obj.clear?(:b).should be_false
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should write ordered" do
|
138
|
+
io = StringIO.new
|
139
|
+
@obj.write(io)
|
140
|
+
|
141
|
+
io.rewind
|
142
|
+
io.read.should == "\x01\x02"
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should read ordered" do
|
146
|
+
io = StringIO.new "\x03\x04"
|
147
|
+
@obj.read(io)
|
148
|
+
|
149
|
+
@obj.a.should == 3
|
150
|
+
@obj.b.should == 4
|
151
|
+
end
|
152
|
+
|
153
|
+
it "should return a snapshot" do
|
154
|
+
snap = @obj.snapshot
|
155
|
+
snap.a.should == 1
|
156
|
+
snap.b.should == 2
|
157
|
+
snap.should == { "a" => 1, "b" => 2 }
|
158
|
+
end
|
159
|
+
|
160
|
+
it "should return field_names" do
|
161
|
+
@obj.field_names.should == ["a", "b"]
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should fail on unknown method call" do
|
165
|
+
lambda { @obj.does_not_exist }.should raise_error(NoMethodError)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
describe BinData::MultiValue, "with nested structs" do
|
170
|
+
before(:all) do
|
171
|
+
eval <<-END
|
172
|
+
class MultiValueInner1 < BinData::MultiValue
|
173
|
+
int8 :w, :initial_value => 3
|
174
|
+
int8 :x, :value => :the_val
|
175
|
+
end
|
176
|
+
|
177
|
+
class MultiValueInner2 < BinData::MultiValue
|
178
|
+
int8 :y, :value => lambda { parent.b.w }
|
179
|
+
int8 :z
|
180
|
+
end
|
181
|
+
|
182
|
+
class MultiValueOuter < BinData::MultiValue
|
183
|
+
int8 :a, :initial_value => 6
|
184
|
+
multi_value_inner1 :b, :the_val => :a
|
185
|
+
multi_value_inner2 nil
|
186
|
+
end
|
187
|
+
END
|
188
|
+
end
|
189
|
+
|
190
|
+
before(:each) do
|
191
|
+
@obj = MultiValueOuter.new
|
192
|
+
end
|
193
|
+
|
194
|
+
it "should included nested field names" do
|
195
|
+
@obj.field_names.should == ["a", "b", "y", "z"]
|
196
|
+
end
|
197
|
+
|
198
|
+
it "should access nested fields" do
|
199
|
+
@obj.a.should == 6
|
200
|
+
@obj.b.w.should == 3
|
201
|
+
@obj.b.x.should == 6
|
202
|
+
@obj.y.should == 3
|
203
|
+
end
|
204
|
+
|
205
|
+
it "should return correct offset of" do
|
206
|
+
@obj.offset_of("b").should == 1
|
207
|
+
@obj.offset_of("y").should == 3
|
208
|
+
@obj.offset_of("z").should == 4
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
describe BinData::MultiValue, "with an endian defined" do
|
213
|
+
before(:all) do
|
214
|
+
eval <<-END
|
215
|
+
class MultiValueWithEndian < BinData::MultiValue
|
216
|
+
endian :little
|
217
|
+
|
218
|
+
uint16 :a
|
219
|
+
float :b
|
220
|
+
array :c, :type => :int8, :initial_length => 2
|
221
|
+
choice :d, :choices => [ [:uint16], [:uint32] ], :selection => 1
|
222
|
+
struct :e, :fields => [ [:uint16, :f], [:uint32be, :g] ]
|
223
|
+
struct :h, :fields => [ [:struct, :i, {:fields => [[:uint16, :j]]}] ]
|
224
|
+
end
|
225
|
+
END
|
226
|
+
end
|
227
|
+
|
228
|
+
before(:each) do
|
229
|
+
@obj = MultiValueWithEndian.new
|
230
|
+
end
|
231
|
+
|
232
|
+
it "should use correct endian" do
|
233
|
+
@obj.a = 1
|
234
|
+
@obj.b = 2.0
|
235
|
+
@obj.c[0] = 3
|
236
|
+
@obj.c[1] = 4
|
237
|
+
@obj.d = 5
|
238
|
+
@obj.e.f = 6
|
239
|
+
@obj.e.g = 7
|
240
|
+
@obj.h.i.j = 8
|
241
|
+
|
242
|
+
expected = [1, 2.0, 3, 4, 5, 6, 7, 8].pack('veCCVvNv')
|
243
|
+
|
244
|
+
io = StringIO.new
|
245
|
+
@obj.write(io)
|
246
|
+
|
247
|
+
io.rewind
|
248
|
+
io.read.should == expected
|
249
|
+
end
|
250
|
+
end
|