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.

@@ -6,7 +6,11 @@ require 'bindata/int'
6
6
  require 'bindata/lazy'
7
7
  require 'bindata/struct'
8
8
 
9
- describe "Instantiating a Choice" do
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 "A Choice with several choices" do
71
+ describe BinData::Choice, "with choices array" do
26
72
  before(:each) do
27
- # allow specifications to select the choice
28
- @env = BinData::LazyEvalEnv.new
29
- @env.class.class_eval { attr_accessor :choose }
30
-
31
- @data = BinData::Choice.new({:choices => [[:int8, {:initial_value => 3}],
32
- [:int16le, {:initial_value => 5}],
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
- @env.choose = 0
43
- @data.value.should eql(3)
44
- @env.choose = 1
45
- @data.value.should eql(5)
46
- @env.choose = 2
47
- @data.value.should eql(0)
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 not be able to select an invalid choice" do
55
- @env.choose = -1
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 interact directly with the choice" do
62
- @env.choose = 0
63
- @data.value = 17
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
- @env.choose = 0
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
- @env.choose = 1
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 eql(2)
112
+ @data.num_bytes.should == 2
81
113
  @data.field_names.should be_empty
82
- @data.value.should eql(17)
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
- io = StringIO.new
85
- @data.write(io)
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
- @data.clear
88
- @data.clear?.should be_true
89
- @data.value.should eql(5)
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
- io.rewind
92
- @data.read(io)
93
- @data.value.should eql(17)
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
- @data.snapshot.should eql(17)
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 delegate methods to the selected complex choice" do
99
- @env.choose = 3
100
- @data.find_obj_for_name("a").should_not be_nil
101
- @data.field_names.should eql(["a"])
102
- @data.num_bytes.should eql(1)
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
@@ -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 eql(0)
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 eql(0)
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 eql(clamped_val)
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 eql(str)
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 eql(clamped_val)
85
+ data.value.should == clamped_val
86
86
  end
87
87
 
88
88
  # return test data for testing unsigned ints
@@ -12,31 +12,34 @@ class MockDataObject
12
12
  end
13
13
  end
14
14
 
15
- describe "A single environment" do
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 eql('o1')
25
- @e1.lazy_eval(lambda { v1 }).should eql('v1')
26
- @e1.lazy_eval(:o1, :o1 => 'o1').should eql('o1')
27
- @e1.lazy_eval(:v1).should eql('v1')
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 eql('o1')
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 eql('v1')
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 eql('o1')
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 "An environment with one parent" do
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 eql('p2')
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 eql('f2')
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 eql('p2')
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 eql('v1')
82
+ @e1.lazy_eval(:common2).should == 'v1'
80
83
  end
81
84
  end
82
85
 
83
- describe "A nested environment" do
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 eql('p3')
109
- @e1.lazy_eval(lambda { parent.parent.p4 }).should eql('p4')
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 eql('l4')
114
- @e1.lazy_eval(lambda { s2 }).should eql('s4')
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 eql('p3')
119
- @e1.lazy_eval(lambda { p4 }).should eql('p4')
120
- @e1.lazy_eval(lambda { v2 }).should eql('v2')
121
- @e1.lazy_eval(lambda { s3 }).should eql('s4')
122
- @e1.lazy_eval(lambda { fs2 }).should eql('s4')
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