bindata 0.5.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/COPYING +52 -0
- data/ChangeLog +9 -0
- data/GPL +339 -0
- data/INSTALL +7 -0
- data/README +215 -0
- data/TODO +14 -0
- data/examples/gzip.rb +174 -0
- data/lib/bindata.rb +13 -0
- data/lib/bindata/array.rb +160 -0
- data/lib/bindata/base.rb +260 -0
- data/lib/bindata/choice.rb +120 -0
- data/lib/bindata/int.rb +171 -0
- data/lib/bindata/lazy.rb +71 -0
- data/lib/bindata/registry.rb +37 -0
- data/lib/bindata/single.rb +170 -0
- data/lib/bindata/string.rb +98 -0
- data/lib/bindata/stringz.rb +83 -0
- data/lib/bindata/struct.rb +292 -0
- data/spec/array_spec.rb +121 -0
- data/spec/base_spec.rb +194 -0
- data/spec/choice_spec.rb +105 -0
- data/spec/int_spec.rb +141 -0
- data/spec/lazy_spec.rb +120 -0
- data/spec/registry_spec.rb +47 -0
- data/spec/single_spec.rb +210 -0
- data/spec/spec_common.rb +10 -0
- data/spec/string_spec.rb +205 -0
- data/spec/stringz_spec.rb +159 -0
- data/spec/struct_spec.rb +190 -0
- metadata +78 -0
data/spec/lazy_spec.rb
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require File.expand_path(File.dirname(__FILE__)) + '/spec_common'
|
4
|
+
require 'bindata/lazy'
|
5
|
+
|
6
|
+
# A mock data object that can substitute for BinData::Simple or BinData::Struct
|
7
|
+
class MockDataObject
|
8
|
+
def initialize(value = nil, fields = {})
|
9
|
+
@value = value
|
10
|
+
@fields = fields
|
11
|
+
end
|
12
|
+
attr_accessor :value
|
13
|
+
|
14
|
+
def field_names
|
15
|
+
@fields.keys.collect { |k| k.to_s }
|
16
|
+
end
|
17
|
+
def respond_to?(symbol, include_private = false)
|
18
|
+
field_names.include?(symbol.id2name) ? true : super
|
19
|
+
end
|
20
|
+
def method_missing(symbol, *args)
|
21
|
+
@fields[symbol] || super
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context "A single environment" do
|
26
|
+
setup do
|
27
|
+
@do1 = MockDataObject.new('v1', :f1 => 'f1')
|
28
|
+
@e1 = BinData::LazyEvalEnv.new
|
29
|
+
@e1.data_object = @do1
|
30
|
+
@e1.params = {:p1 => 'p1'}
|
31
|
+
end
|
32
|
+
|
33
|
+
specify "should evaluate value" do
|
34
|
+
@e1.lazy_eval(lambda { value }).should == 'v1'
|
35
|
+
end
|
36
|
+
|
37
|
+
specify "should evaluate index" do
|
38
|
+
@e1.index = 7
|
39
|
+
@e1.lazy_eval(lambda { index }).should == 7
|
40
|
+
end
|
41
|
+
|
42
|
+
specify "should evaluate offset" do
|
43
|
+
@e1.offset = 9
|
44
|
+
@e1.lazy_eval(lambda { offset }).should == 9
|
45
|
+
end
|
46
|
+
|
47
|
+
specify "should not resolve any unknown fields" do
|
48
|
+
lambda { @e1.lazy_eval(lambda { unknown }) }.should raise_error(NameError)
|
49
|
+
lambda { @e1.lazy_eval(lambda { p1 }) }.should raise_error(NameError)
|
50
|
+
lambda { @e1.lazy_eval(lambda { f1 }) }.should raise_error(NameError)
|
51
|
+
end
|
52
|
+
|
53
|
+
specify "should accept symbols as a shortcut to lambda" do
|
54
|
+
@e1.index = 7
|
55
|
+
@e1.offset = 9
|
56
|
+
@e1.lazy_eval(:value).should == 'v1'
|
57
|
+
@e1.lazy_eval(:index).should == 7
|
58
|
+
@e1.lazy_eval(:offset).should == 9
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context "An environment with one parent" do
|
63
|
+
setup do
|
64
|
+
@do2 = MockDataObject.new(nil, :f2 => 'f2', :common => 'field2')
|
65
|
+
@do1 = MockDataObject.new
|
66
|
+
|
67
|
+
@e2 = BinData::LazyEvalEnv.new
|
68
|
+
@e1 = BinData::LazyEvalEnv.new(@e2)
|
69
|
+
|
70
|
+
@e2.data_object = @do2
|
71
|
+
@e1.data_object = @do1
|
72
|
+
|
73
|
+
@e2.params = {:p2 => 'p2', :l2 => lambda { 'l2' }, :common => 'param2'}
|
74
|
+
end
|
75
|
+
|
76
|
+
specify "should evaluate parent parameter" do
|
77
|
+
@e1.lazy_eval(:p2).should == 'p2'
|
78
|
+
end
|
79
|
+
|
80
|
+
specify "should evaluate parent field" do
|
81
|
+
@e1.lazy_eval(:f2).should == 'f2'
|
82
|
+
end
|
83
|
+
|
84
|
+
specify "should prefer parent param over parent field" do
|
85
|
+
@e1.lazy_eval(:common).should == 'param2'
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context "A nested environment" do
|
90
|
+
setup do
|
91
|
+
@do4 = MockDataObject.new(nil, :f4 => 'f4')
|
92
|
+
@do3 = MockDataObject.new(nil, :f3 => 'f3')
|
93
|
+
@do2 = MockDataObject.new(nil, :f2 => 'f2')
|
94
|
+
@do1 = MockDataObject.new(nil, :f1 => 'f1')
|
95
|
+
|
96
|
+
@e4 = BinData::LazyEvalEnv.new
|
97
|
+
@e3 = BinData::LazyEvalEnv.new(@e4)
|
98
|
+
@e2 = BinData::LazyEvalEnv.new(@e3)
|
99
|
+
@e1 = BinData::LazyEvalEnv.new(@e2)
|
100
|
+
|
101
|
+
@e4.data_object = @do4
|
102
|
+
@e3.data_object = @do3
|
103
|
+
@e2.data_object = @do2
|
104
|
+
@e1.data_object = @do1
|
105
|
+
|
106
|
+
@e4.params = {:p4 => 'p4', :s4 => 's4', :l4 => 'l4'}
|
107
|
+
@e3.params = {:p3 => 'p3', :s3 => :s4, :l3 => lambda { l4 }}
|
108
|
+
@e2.params = {:p2 => 'p2', :s2 => :s3, :l2 => lambda { l3 }}
|
109
|
+
end
|
110
|
+
|
111
|
+
specify "should access parent environments" do
|
112
|
+
@e1.lazy_eval(lambda { parent.p3 }).should == 'p3'
|
113
|
+
@e1.lazy_eval(lambda { parent.parent.p4 }).should == 'p4'
|
114
|
+
end
|
115
|
+
|
116
|
+
specify "should cascade lambdas" do
|
117
|
+
@e1.lazy_eval(lambda { l2 }).should == 'l4'
|
118
|
+
@e1.lazy_eval(lambda { s2 }).should == 's4'
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require File.expand_path(File.dirname(__FILE__)) + '/spec_common'
|
4
|
+
require 'bindata/registry'
|
5
|
+
|
6
|
+
context "The Registry" do
|
7
|
+
setup do
|
8
|
+
@r = BinData::Registry.instance
|
9
|
+
end
|
10
|
+
|
11
|
+
specify "should be a singleton" do
|
12
|
+
BinData::Registry.instance.should equal(BinData::Registry.instance)
|
13
|
+
end
|
14
|
+
|
15
|
+
specify "should lookup registered names" do
|
16
|
+
A = Class.new
|
17
|
+
B = Class.new
|
18
|
+
@r.register('ASubClass', A)
|
19
|
+
@r.register('AnotherSubClass', B)
|
20
|
+
|
21
|
+
@r.lookup('a_sub_class').should == A
|
22
|
+
@r.lookup('another_sub_class').should == B
|
23
|
+
end
|
24
|
+
|
25
|
+
specify "should not lookup unregistered names" do
|
26
|
+
@r.lookup('a_non_existent_sub_class').should be_nil
|
27
|
+
end
|
28
|
+
|
29
|
+
specify "should convert CamelCase to underscores" do
|
30
|
+
@r.register('CamelCase', A).should == 'camel_case'
|
31
|
+
end
|
32
|
+
|
33
|
+
specify "should convert adjacent caps camelCase to underscores" do
|
34
|
+
@r.register('XYZCamelCase', A).should == 'xyz_camel_case'
|
35
|
+
end
|
36
|
+
|
37
|
+
specify "should ignore the outer nestings of classes" do
|
38
|
+
@r.register('A::B::C', A).should == 'c'
|
39
|
+
end
|
40
|
+
|
41
|
+
specify "should allow overriding of registered classes" do
|
42
|
+
@r.register('A', A)
|
43
|
+
@r.register('A', B)
|
44
|
+
|
45
|
+
@r.lookup('a').should == B
|
46
|
+
end
|
47
|
+
end
|
data/spec/single_spec.rb
ADDED
@@ -0,0 +1,210 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require File.expand_path(File.dirname(__FILE__)) + '/spec_common'
|
4
|
+
require 'bindata/single'
|
5
|
+
|
6
|
+
# An implementation of a unsigned 4 byte integer.
|
7
|
+
class ConcreteSingle < BinData::Single
|
8
|
+
def val_to_str(val) [val].pack("V") end
|
9
|
+
def read_val(io) readbytes(io, 4).unpack("V")[0] end
|
10
|
+
def sensible_default() 0 end
|
11
|
+
|
12
|
+
def in_read?() @in_read end
|
13
|
+
end
|
14
|
+
|
15
|
+
context "The sample implementation of Single" do
|
16
|
+
specify "should have symmetric IO" do
|
17
|
+
io = StringIO.new
|
18
|
+
data = ConcreteSingle.new
|
19
|
+
data.value = 42
|
20
|
+
data.write(io)
|
21
|
+
|
22
|
+
io.rewind
|
23
|
+
data = ConcreteSingle.new
|
24
|
+
data.read(io)
|
25
|
+
data.value.should == 42
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context "The class Single" do
|
30
|
+
specify "should register subclasses" do
|
31
|
+
BinData::Single.lookup(:concrete_single).should == ConcreteSingle
|
32
|
+
end
|
33
|
+
|
34
|
+
specify "should read and return a value" do
|
35
|
+
io = StringIO.new([123456].pack("V"))
|
36
|
+
ConcreteSingle.read(io).should == 123456
|
37
|
+
data = ConcreteSingle.new
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context "A Single object" do
|
42
|
+
specify "should conform to rule 1 for returning a value" do
|
43
|
+
data = ConcreteSingle.new(:value => 5)
|
44
|
+
data.should_not be_in_read
|
45
|
+
data.value.should == 5
|
46
|
+
end
|
47
|
+
|
48
|
+
specify "should conform to rule 2 for returning a value" do
|
49
|
+
io = StringIO.new([42].pack("V"))
|
50
|
+
data = ConcreteSingle.new(:value => 5)
|
51
|
+
data.do_read(io)
|
52
|
+
data.should be_in_read
|
53
|
+
data.value.should == 42
|
54
|
+
end
|
55
|
+
|
56
|
+
specify "should conform to rule 3 for returning a value" do
|
57
|
+
data = ConcreteSingle.new(:initial_value => 5)
|
58
|
+
data.should be_clear
|
59
|
+
data.value.should == 5
|
60
|
+
end
|
61
|
+
|
62
|
+
specify "should conform to rule 4 for returning a value" do
|
63
|
+
data = ConcreteSingle.new(:initial_value => 5)
|
64
|
+
data.value = 17
|
65
|
+
data.should_not be_clear
|
66
|
+
data.value.should == 17
|
67
|
+
end
|
68
|
+
|
69
|
+
specify "should conform to rule 5 for returning a value" do
|
70
|
+
data = ConcreteSingle.new
|
71
|
+
data.should be_clear
|
72
|
+
data.value.should == 0
|
73
|
+
end
|
74
|
+
|
75
|
+
specify "should conform to rule 6 for returning a value" do
|
76
|
+
data = ConcreteSingle.new
|
77
|
+
data.value = 8
|
78
|
+
data.should_not be_clear
|
79
|
+
data.value.should == 8
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context "A new Single object" do
|
84
|
+
setup do
|
85
|
+
@data = ConcreteSingle.new
|
86
|
+
end
|
87
|
+
|
88
|
+
specify "should not allow both :initial_value and :value" do
|
89
|
+
params = {:initial_value => 1, :value => 2}
|
90
|
+
lambda { ConcreteSingle.new(params) }.should raise_error(ArgumentError)
|
91
|
+
end
|
92
|
+
|
93
|
+
specify "should have a sensible value" do
|
94
|
+
@data.value.should == 0
|
95
|
+
end
|
96
|
+
|
97
|
+
specify "should allowing setting and retrieving value" do
|
98
|
+
@data.value = 5
|
99
|
+
@data.value.should == 5
|
100
|
+
end
|
101
|
+
|
102
|
+
specify "should be clear" do
|
103
|
+
@data.should be_clear
|
104
|
+
end
|
105
|
+
|
106
|
+
specify "should not be clear after setting value" do
|
107
|
+
@data.value = 5
|
108
|
+
@data.should_not be_clear
|
109
|
+
end
|
110
|
+
|
111
|
+
specify "should not be clear after reading" do
|
112
|
+
io = StringIO.new([123456].pack("V"))
|
113
|
+
@data.read(io)
|
114
|
+
@data.should_not be_clear
|
115
|
+
end
|
116
|
+
|
117
|
+
specify "should return num_bytes" do
|
118
|
+
@data.num_bytes.should == 4
|
119
|
+
end
|
120
|
+
|
121
|
+
specify "should not contain any field names" do
|
122
|
+
@data.field_names.should be_empty
|
123
|
+
end
|
124
|
+
|
125
|
+
specify "should return a snapshot" do
|
126
|
+
@data.value = 5
|
127
|
+
@data.snapshot.should == 5
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context "A Single with :initial_value" do
|
132
|
+
setup do
|
133
|
+
@data = ConcreteSingle.new(:initial_value => 5)
|
134
|
+
end
|
135
|
+
|
136
|
+
specify "should return that initial value before reading or being set" do
|
137
|
+
@data.value.should == 5
|
138
|
+
end
|
139
|
+
|
140
|
+
specify "should forget :initial_value after being set" do
|
141
|
+
@data.value = 17
|
142
|
+
@data.value.should_not == 5
|
143
|
+
end
|
144
|
+
|
145
|
+
specify "should forget :initial_value after reading" do
|
146
|
+
io = StringIO.new([56].pack("V"))
|
147
|
+
@data.read(io)
|
148
|
+
@data.value.should_not == 5
|
149
|
+
end
|
150
|
+
|
151
|
+
specify "should remember :initial_value after being cleared" do
|
152
|
+
@data.value = 17
|
153
|
+
@data.clear
|
154
|
+
@data.value.should == 5
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
context "A Single with :value" do
|
159
|
+
setup do
|
160
|
+
@data = ConcreteSingle.new(:value => 5)
|
161
|
+
end
|
162
|
+
|
163
|
+
specify "should return that :value" do
|
164
|
+
@data.value.should == 5
|
165
|
+
end
|
166
|
+
|
167
|
+
specify "should change during reading" do
|
168
|
+
io = StringIO.new([56].pack("V"))
|
169
|
+
@data.do_read(io)
|
170
|
+
@data.value.should == 56
|
171
|
+
@data.done_read
|
172
|
+
end
|
173
|
+
|
174
|
+
specify "should not change after reading" do
|
175
|
+
io = StringIO.new([56].pack("V"))
|
176
|
+
@data.read(io)
|
177
|
+
@data.value.should == 5
|
178
|
+
end
|
179
|
+
|
180
|
+
specify "should not be able to change the value" do
|
181
|
+
@data.value = 17
|
182
|
+
@data.value.should == 5
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
context "A Single with :check_value" do
|
187
|
+
setup do
|
188
|
+
@io = StringIO.new([34].pack("V"))
|
189
|
+
end
|
190
|
+
|
191
|
+
specify "should succeed when check_value is non boolean and correct" do
|
192
|
+
data = ConcreteSingle.new(:check_value => 34)
|
193
|
+
lambda { data.read(@io) }.should_not raise_error
|
194
|
+
end
|
195
|
+
|
196
|
+
specify "should fail when check_value is non boolean and incorrect" do
|
197
|
+
data = ConcreteSingle.new(:check_value => lambda { 123 * 5 })
|
198
|
+
lambda { data.read(@io) }.should raise_error(BinData::ValidityError)
|
199
|
+
end
|
200
|
+
|
201
|
+
specify "should succeed when check_value is boolean and true" do
|
202
|
+
data = ConcreteSingle.new(:check_value => lambda { (value % 2) == 0})
|
203
|
+
lambda { data.read(@io) }.should_not raise_error
|
204
|
+
end
|
205
|
+
|
206
|
+
specify "should fail when check_value is boolean and false" do
|
207
|
+
data = ConcreteSingle.new(:check_value => lambda { value > 100 })
|
208
|
+
lambda { data.read(@io) }.should raise_error(BinData::ValidityError)
|
209
|
+
end
|
210
|
+
end
|
data/spec/spec_common.rb
ADDED
data/spec/string_spec.rb
ADDED
@@ -0,0 +1,205 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require File.expand_path(File.dirname(__FILE__)) + '/spec_common'
|
4
|
+
require 'bindata/string'
|
5
|
+
|
6
|
+
context "Test mutual exclusion of parameters" do
|
7
|
+
specify ":value and :initial_value" do
|
8
|
+
params = {:value => "", :initial_value => ""}
|
9
|
+
lambda { BinData::String.new(params) }.should raise_error(ArgumentError)
|
10
|
+
end
|
11
|
+
|
12
|
+
specify ":length and :initial_length" do
|
13
|
+
params = {:length => 5, :initial_length => 5}
|
14
|
+
lambda { BinData::String.new(params) }.should raise_error(ArgumentError)
|
15
|
+
end
|
16
|
+
|
17
|
+
specify ":initial_value and :initial_length" do
|
18
|
+
params = {:initial_value => "", :initial_length => 5}
|
19
|
+
lambda { BinData::String.new(params) }.should raise_error(ArgumentError)
|
20
|
+
end
|
21
|
+
|
22
|
+
specify ":value and :length" do
|
23
|
+
params = {:value => "", :length => 5}
|
24
|
+
lambda { BinData::String.new(params) }.should raise_error(ArgumentError)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "A String with :initial_length" do
|
29
|
+
setup do
|
30
|
+
@str = BinData::String.new(:initial_length => 5)
|
31
|
+
end
|
32
|
+
|
33
|
+
specify "should set num_bytes" do
|
34
|
+
@str.num_bytes.should == 5
|
35
|
+
end
|
36
|
+
|
37
|
+
specify "should fill value with pad_char" do
|
38
|
+
@str.value.should == "\0\0\0\0\0"
|
39
|
+
end
|
40
|
+
|
41
|
+
specify "should read :initial_length bytes" do
|
42
|
+
io = StringIO.new("abcdefghij")
|
43
|
+
@str.read(io)
|
44
|
+
@str.value.should == "abcde"
|
45
|
+
end
|
46
|
+
|
47
|
+
specify "should forget :initial_length after value is set" do
|
48
|
+
@str.value = "abc"
|
49
|
+
@str.num_bytes.should == 3
|
50
|
+
end
|
51
|
+
|
52
|
+
specify "should remember :initial_length after value is cleared" do
|
53
|
+
@str.value = "abc"
|
54
|
+
@str.num_bytes.should == 3
|
55
|
+
@str.clear
|
56
|
+
@str.num_bytes.should == 5
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context "A String with :length" do
|
61
|
+
setup do
|
62
|
+
@str = BinData::String.new(:length => 5)
|
63
|
+
end
|
64
|
+
|
65
|
+
specify "should set num_bytes" do
|
66
|
+
@str.num_bytes.should == 5
|
67
|
+
end
|
68
|
+
|
69
|
+
specify "should fill value with pad_char" do
|
70
|
+
@str.value.should == "\0\0\0\0\0"
|
71
|
+
end
|
72
|
+
|
73
|
+
specify "should retain :length after value is set" do
|
74
|
+
@str.value = "abcdefghij"
|
75
|
+
@str.num_bytes.should == 5
|
76
|
+
end
|
77
|
+
|
78
|
+
specify "should read :length bytes" do
|
79
|
+
io = StringIO.new("abcdefghij")
|
80
|
+
@str.read(io)
|
81
|
+
@str.value.should == "abcde"
|
82
|
+
end
|
83
|
+
|
84
|
+
specify "should pad values less than :length" do
|
85
|
+
@str.value = "abc"
|
86
|
+
@str.value.should == "abc\0\0"
|
87
|
+
end
|
88
|
+
|
89
|
+
specify "should accept values exactly :length" do
|
90
|
+
@str.value = "abcde"
|
91
|
+
@str.value.should == "abcde"
|
92
|
+
end
|
93
|
+
|
94
|
+
specify "should truncate values greater than :length" do
|
95
|
+
@str.value = "abcdefg"
|
96
|
+
@str.value.should == "abcde"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context "A String with :initial_length and :value" do
|
101
|
+
setup do
|
102
|
+
@str = BinData::String.new(:initial_length => 5, :value => "abcdefghij")
|
103
|
+
end
|
104
|
+
|
105
|
+
specify "should use :initial_length before value is read" do
|
106
|
+
@str.num_bytes.should == 5
|
107
|
+
@str.value.should == "abcde"
|
108
|
+
end
|
109
|
+
|
110
|
+
specify "should use :initial_length for reading" do
|
111
|
+
io = StringIO.new("ABCDEFGHIJKLMNOPQRST")
|
112
|
+
@str.read(io)
|
113
|
+
io.pos.should == 5
|
114
|
+
end
|
115
|
+
|
116
|
+
specify "should forget :initial_length after reading" do
|
117
|
+
io = StringIO.new("ABCDEFGHIJKLMNOPQRST")
|
118
|
+
@str.read(io)
|
119
|
+
@str.num_bytes.should == 10
|
120
|
+
@str.value.should == "abcdefghij"
|
121
|
+
end
|
122
|
+
|
123
|
+
specify "should return read value before calling done_read" do
|
124
|
+
io = StringIO.new("ABCDEFGHIJKLMNOPQRST")
|
125
|
+
|
126
|
+
@str.do_read(io)
|
127
|
+
@str.value.should == "ABCDE"
|
128
|
+
|
129
|
+
@str.done_read
|
130
|
+
@str.value.should == "abcdefghij"
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
context "A String with :length and :initial_value" do
|
135
|
+
setup do
|
136
|
+
@str = BinData::String.new(:length => 5, :initial_value => "abcdefghij")
|
137
|
+
end
|
138
|
+
|
139
|
+
specify "should apply :length to :initial_value" do
|
140
|
+
@str.num_bytes.should == 5
|
141
|
+
@str.value.should == "abcde"
|
142
|
+
end
|
143
|
+
|
144
|
+
specify "should forget :initial_value after reading" do
|
145
|
+
io = StringIO.new("ABCDEFGHIJKLMNOPQRST")
|
146
|
+
@str.read(io)
|
147
|
+
io.pos.should == 5
|
148
|
+
@str.num_bytes.should == 5
|
149
|
+
@str.value.should == "ABCDE"
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
context "A String with :pad_char" do
|
154
|
+
specify "should accept a numeric value for :pad_char" do
|
155
|
+
@str = BinData::String.new(:length => 5, :pad_char => 6)
|
156
|
+
@str.value = "abc"
|
157
|
+
@str.value.should == "abc\x06\x06"
|
158
|
+
end
|
159
|
+
|
160
|
+
specify "should accept a character for :pad_char" do
|
161
|
+
@str = BinData::String.new(:length => 5, :pad_char => "R")
|
162
|
+
@str.value = "abc"
|
163
|
+
@str.value.should == "abcRR"
|
164
|
+
end
|
165
|
+
|
166
|
+
specify "should not accept a string for :pad_char" do
|
167
|
+
params = {:length => 5, :pad_char => "RR"}
|
168
|
+
lambda { BinData::String.new(params) }.should raise_error(ArgumentError)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
context "A String with :trim_value" do
|
173
|
+
specify "set false is the default" do
|
174
|
+
str1 = BinData::String.new(:length => 5)
|
175
|
+
str2 = BinData::String.new(:length => 5, :trim_value => false)
|
176
|
+
str1.value = "abc"
|
177
|
+
str2.value = "abc"
|
178
|
+
str1.value.should == "abc\0\0"
|
179
|
+
str2.value.should == "abc\0\0"
|
180
|
+
end
|
181
|
+
|
182
|
+
specify "should trim the value" do
|
183
|
+
str = BinData::String.new(:pad_char => 'R', :trim_value => true)
|
184
|
+
str.value = "abcRR"
|
185
|
+
str.value.should == "abc"
|
186
|
+
end
|
187
|
+
|
188
|
+
specify "should not affect num_bytes" do
|
189
|
+
str = BinData::String.new(:pad_char => 'R', :trim_value => true)
|
190
|
+
str.value = "abcRR"
|
191
|
+
str.num_bytes.should == 5
|
192
|
+
end
|
193
|
+
|
194
|
+
specify "should trim if last char is :pad_char" do
|
195
|
+
str = BinData::String.new(:pad_char => 'R', :trim_value => true)
|
196
|
+
str.value = "abcRR"
|
197
|
+
str.value.should == "abc"
|
198
|
+
end
|
199
|
+
|
200
|
+
specify "should not trim if value contains :pad_char not at the end" do
|
201
|
+
str = BinData::String.new(:pad_char => 'R', :trim_value => true)
|
202
|
+
str.value = "abcRRde"
|
203
|
+
str.value.should == "abcRRde"
|
204
|
+
end
|
205
|
+
end
|