bindata 1.5.1 → 1.6.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.rdoc +7 -0
- data/NEWS.rdoc +11 -0
- data/Rakefile +6 -1
- data/bindata.gemspec +2 -1
- data/doc/manual.md +17 -9
- data/examples/gzip.rb +2 -2
- data/examples/list.rb +2 -2
- data/lib/bindata/alignment.rb +4 -9
- data/lib/bindata/array.rb +57 -51
- data/lib/bindata/base.rb +13 -110
- data/lib/bindata/base_primitive.rb +130 -75
- data/lib/bindata/bits.rb +5 -7
- data/lib/bindata/choice.rb +24 -32
- data/lib/bindata/dsl.rb +1 -6
- data/lib/bindata/framework.rb +81 -0
- data/lib/bindata/int.rb +5 -7
- data/lib/bindata/name.rb +28 -0
- data/lib/bindata/offset.rb +42 -53
- data/lib/bindata/params.rb +33 -38
- data/lib/bindata/struct.rb +2 -6
- data/lib/bindata/trace.rb +16 -16
- data/lib/bindata/version.rb +1 -1
- data/lib/bindata/virtual.rb +3 -3
- data/{spec/alignment_spec.rb → test/alignment_test.rb} +17 -16
- data/test/array_test.rb +371 -0
- data/test/base_primitive_test.rb +312 -0
- data/test/base_test.rb +183 -0
- data/{spec/bits_spec.rb → test/bits_test.rb} +59 -59
- data/test/choice_test.rb +260 -0
- data/{spec/spec_common.rb → test/common.rb} +33 -18
- data/test/count_bytes_remaining_test.rb +41 -0
- data/{spec/deprecated_spec.rb → test/deprecated_test.rb} +5 -7
- data/test/float_test.rb +72 -0
- data/{spec/int_spec.rb → test/int_test.rb} +34 -43
- data/{spec/io_spec.rb → test/io_test.rb} +70 -71
- data/{spec/lazy_spec.rb → test/lazy_test.rb} +38 -39
- data/test/offset_test.rb +93 -0
- data/test/params_test.rb +144 -0
- data/{spec/primitive_spec.rb → test/primitive_test.rb} +42 -54
- data/{spec/record_spec.rb → test/record_test.rb} +133 -154
- data/test/registry_test.rb +104 -0
- data/test/rest_test.rb +29 -0
- data/test/skip_test.rb +28 -0
- data/{spec/string_spec.rb → test/string_test.rb} +96 -97
- data/test/stringz_test.rb +127 -0
- data/{spec/struct_spec.rb → test/struct_test.rb} +119 -120
- data/{spec/system_spec.rb → test/system_test.rb} +66 -106
- metadata +39 -38
- data/lib/a.rb +0 -24
- data/spec/array_spec.rb +0 -331
- data/spec/base_primitive_spec.rb +0 -238
- data/spec/base_spec.rb +0 -376
- data/spec/choice_spec.rb +0 -263
- data/spec/count_bytes_remaining_spec.rb +0 -38
- data/spec/example.rb +0 -21
- data/spec/float_spec.rb +0 -37
- data/spec/registry_spec.rb +0 -108
- data/spec/rest_spec.rb +0 -26
- data/spec/skip_spec.rb +0 -27
- data/spec/stringz_spec.rb +0 -118
- data/tasks/rspec.rake +0 -17
data/test/base_test.rb
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "common"))
|
4
|
+
|
5
|
+
describe "BinData::Base", "framework" do
|
6
|
+
class FrameworkBase < BinData::Base
|
7
|
+
class << self
|
8
|
+
attr_accessor :calls
|
9
|
+
def record_calls(&block)
|
10
|
+
self.calls = []
|
11
|
+
block.call
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize_instance
|
16
|
+
self.class.calls << :initialize_instance
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize_shared_instance
|
20
|
+
self.class.calls << :initialize_shared_instance
|
21
|
+
end
|
22
|
+
|
23
|
+
expose_methods_for_testing
|
24
|
+
end
|
25
|
+
|
26
|
+
let(:obj) do
|
27
|
+
FrameworkBase.record_calls { FrameworkBase.new }
|
28
|
+
end
|
29
|
+
|
30
|
+
it "raises errors on unimplemented methods" do
|
31
|
+
lambda { obj.clear? }.must_raise NotImplementedError
|
32
|
+
lambda { obj.assign(nil) }.must_raise NotImplementedError
|
33
|
+
lambda { obj.snapshot }.must_raise NotImplementedError
|
34
|
+
lambda { obj.do_read(nil) }.must_raise NotImplementedError
|
35
|
+
lambda { obj.do_write(nil) }.must_raise NotImplementedError
|
36
|
+
lambda { obj.do_num_bytes }.must_raise NotImplementedError
|
37
|
+
end
|
38
|
+
|
39
|
+
it "calls initialize methods in order" do
|
40
|
+
FrameworkBase.record_calls { FrameworkBase.new }
|
41
|
+
FrameworkBase.calls.must_equal [:initialize_shared_instance, :initialize_instance]
|
42
|
+
end
|
43
|
+
|
44
|
+
it "does not call #initialize_shared_instance for prototypes" do
|
45
|
+
prototype = obj
|
46
|
+
FrameworkBase.record_calls { prototype.new }
|
47
|
+
FrameworkBase.calls.must_equal [:initialize_instance]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe BinData::Base, "ArgExtractor" do
|
52
|
+
class ParamParserBase < BinData::Base
|
53
|
+
attr_reader :params
|
54
|
+
attr_reader :val
|
55
|
+
|
56
|
+
def assign(v)
|
57
|
+
@val = v
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
it "parses parameters" do
|
62
|
+
par = BinData::Base.new
|
63
|
+
data = [
|
64
|
+
[[3 ], 3, [], nil],
|
65
|
+
[[3, par], 3, [], par],
|
66
|
+
[[ {:a => 1} ], nil, [:a], nil],
|
67
|
+
[[ {:a => 1}, par], nil, [:a], par],
|
68
|
+
[[3, {:a => 1} ], 3, [:a], nil],
|
69
|
+
[[3, {:a => 1}, par], 3, [:a], par],
|
70
|
+
]
|
71
|
+
|
72
|
+
data.each do |el|
|
73
|
+
args, val, param_keys, parent = *el
|
74
|
+
obj = ParamParserBase.new(*args)
|
75
|
+
obj.val.must_be_same_as val
|
76
|
+
obj.params.keys.must_equal param_keys
|
77
|
+
obj.parent.must_be_same_as parent
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe BinData::Base do
|
83
|
+
class BaseStub < BinData::Base
|
84
|
+
# Override to avoid NotImplemented errors
|
85
|
+
def clear?; end
|
86
|
+
def assign(x); @data = x; end
|
87
|
+
def snapshot; @data; end
|
88
|
+
def do_read(io) end
|
89
|
+
def do_write(io) end
|
90
|
+
def do_num_bytes; end
|
91
|
+
end
|
92
|
+
|
93
|
+
let(:obj) { BaseStub.new }
|
94
|
+
|
95
|
+
it "::bindata_name returns lowercased name" do
|
96
|
+
BaseStub.bindata_name.must_equal "base_stub"
|
97
|
+
end
|
98
|
+
|
99
|
+
it "::read instantiates self" do
|
100
|
+
BaseStub.read("").must_be_instance_of BaseStub
|
101
|
+
end
|
102
|
+
|
103
|
+
it "#read returns self" do
|
104
|
+
obj.read("").must_equal obj
|
105
|
+
end
|
106
|
+
|
107
|
+
it "#write returns self" do
|
108
|
+
obj.write("").must_equal obj
|
109
|
+
end
|
110
|
+
|
111
|
+
it "#inspect is forwarded to snapshot" do
|
112
|
+
obj.stub :snapshot, [1, 2, 3] do
|
113
|
+
obj.inspect.must_equal obj.snapshot.inspect
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
it "#to_s is forwarded to snapshot" do
|
118
|
+
obj.stub :snapshot, [1, 2, 3] do
|
119
|
+
obj.to_s.must_equal obj.snapshot.to_s
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
it "pretty prints object as snapshot" do
|
124
|
+
actual_io = StringIO.new
|
125
|
+
expected_io = StringIO.new
|
126
|
+
|
127
|
+
obj.stub :snapshot, [1, 2, 3] do
|
128
|
+
require 'pp'
|
129
|
+
PP.pp(obj, actual_io)
|
130
|
+
PP.pp(obj.snapshot, expected_io)
|
131
|
+
end
|
132
|
+
|
133
|
+
actual_io.value.must_equal expected_io.value
|
134
|
+
end
|
135
|
+
|
136
|
+
it "#write writes the same as #to_binary_s" do
|
137
|
+
class WriteToSBase < BaseStub
|
138
|
+
def do_write(io) io.writebytes("abc"); end
|
139
|
+
end
|
140
|
+
|
141
|
+
obj = WriteToSBase.new
|
142
|
+
io = StringIO.new
|
143
|
+
obj.write(io)
|
144
|
+
io.value.must_equal obj.to_binary_s
|
145
|
+
end
|
146
|
+
|
147
|
+
it "#read is forwarded to #do_read" do
|
148
|
+
calls = []
|
149
|
+
called_clear = lambda { |*a| calls << :clear }
|
150
|
+
called_do_read = lambda { |*a| calls << :do_read }
|
151
|
+
|
152
|
+
obj.stub :clear, called_clear do
|
153
|
+
obj.stub :do_read, called_do_read do
|
154
|
+
obj.read(nil)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
calls.must_equal [:clear, :do_read]
|
159
|
+
end
|
160
|
+
|
161
|
+
it "#write is forwarded to #do_write" do
|
162
|
+
calls = []
|
163
|
+
called_do_write = lambda { |*a| calls << :do_write }
|
164
|
+
|
165
|
+
obj.stub :do_write, called_do_write do
|
166
|
+
obj.write(nil)
|
167
|
+
end
|
168
|
+
|
169
|
+
calls.must_equal [:do_write]
|
170
|
+
end
|
171
|
+
|
172
|
+
it "#num_bytes is forwarded to #do_num_bytes" do
|
173
|
+
obj.stub :do_num_bytes, 42 do
|
174
|
+
obj.num_bytes.must_equal 42
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
it "#num_bytes rounds up fractional values" do
|
179
|
+
obj.stub :do_num_bytes, 42.1 do
|
180
|
+
obj.num_bytes.must_equal 43
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
@@ -1,91 +1,62 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require File.expand_path(File.join(File.dirname(__FILE__), "
|
4
|
-
require 'bindata/bits'
|
3
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "common"))
|
5
4
|
|
6
|
-
|
7
|
-
let(:bit_classes) { [BinData::Bit1, BinData::Bit1le] }
|
8
|
-
|
9
|
-
it "accept true as value" do
|
10
|
-
bit_classes.each do |bit_class|
|
11
|
-
subject = bit_class.new
|
12
|
-
subject.assign(true)
|
13
|
-
subject.should == 1
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
it "accept false as value" do
|
18
|
-
bit_classes.each do |bit_class|
|
19
|
-
subject = bit_class.new
|
20
|
-
subject.assign(false)
|
21
|
-
subject.should == 0
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
it "accept nil as value" do
|
26
|
-
bit_classes.each do |bit_class|
|
27
|
-
subject = bit_class.new
|
28
|
-
subject.assign(nil)
|
29
|
-
subject.should == 0
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
5
|
+
module AllBitfields
|
33
6
|
|
34
|
-
|
35
|
-
|
36
|
-
it "have a sensible value of zero" do
|
7
|
+
def test_has_a_sensible_value_of_zero
|
37
8
|
all_classes do |bit_class|
|
38
|
-
bit_class.new.
|
9
|
+
bit_class.new.must_equal 0
|
39
10
|
end
|
40
11
|
end
|
41
12
|
|
42
|
-
|
13
|
+
def test_avoids_underflow
|
43
14
|
all_classes do |bit_class|
|
44
|
-
|
15
|
+
obj = bit_class.new
|
45
16
|
|
46
|
-
|
47
|
-
|
17
|
+
obj.assign(min_value - 1)
|
18
|
+
obj.must_equal min_value
|
48
19
|
end
|
49
20
|
end
|
50
21
|
|
51
|
-
|
22
|
+
def test_avoids_overflow
|
52
23
|
all_classes do |bit_class|
|
53
|
-
|
24
|
+
obj = bit_class.new
|
54
25
|
|
55
|
-
|
56
|
-
|
26
|
+
obj.assign(max_value + 1)
|
27
|
+
obj.must_equal max_value
|
57
28
|
end
|
58
29
|
end
|
59
30
|
|
60
|
-
|
31
|
+
def test_assign_values
|
61
32
|
all_classes do |bit_class|
|
62
33
|
some_values_within_range.each do |val|
|
63
|
-
|
64
|
-
|
34
|
+
obj = bit_class.new
|
35
|
+
obj.assign(val)
|
65
36
|
|
66
|
-
|
37
|
+
obj.must_equal val
|
67
38
|
end
|
68
39
|
end
|
69
40
|
end
|
70
41
|
|
71
|
-
|
42
|
+
def test_assign_values_from_other_bit_objects
|
72
43
|
all_classes do |bit_class|
|
73
44
|
some_values_within_range.each do |val|
|
74
|
-
|
75
|
-
|
45
|
+
obj = bit_class.new
|
46
|
+
obj.assign(bit_class.new(val))
|
76
47
|
|
77
|
-
|
48
|
+
obj.must_equal val
|
78
49
|
end
|
79
50
|
end
|
80
51
|
end
|
81
52
|
|
82
|
-
|
53
|
+
def test_symmetrically_read_and_write
|
83
54
|
all_classes do |bit_class|
|
84
55
|
some_values_within_range.each do |val|
|
85
|
-
|
86
|
-
|
56
|
+
obj = bit_class.new
|
57
|
+
obj.assign(val)
|
87
58
|
|
88
|
-
|
59
|
+
obj.value_read_from_written.must_equal obj
|
89
60
|
end
|
90
61
|
end
|
91
62
|
end
|
@@ -129,9 +100,9 @@ def generate_bit_classes_to_test(endian)
|
|
129
100
|
end
|
130
101
|
|
131
102
|
describe "Big endian bitfields" do
|
132
|
-
|
103
|
+
include AllBitfields
|
133
104
|
|
134
|
-
before
|
105
|
+
before do
|
135
106
|
@bits = generate_bit_classes_to_test(:big)
|
136
107
|
end
|
137
108
|
|
@@ -140,15 +111,15 @@ describe "Big endian bitfields" do
|
|
140
111
|
nbytes = (nbits + 7) / 8
|
141
112
|
str = [0b1000_0000].pack("C") + "\000" * (nbytes - 1)
|
142
113
|
|
143
|
-
bit_class.read(str).
|
114
|
+
bit_class.read(str).must_equal 1 << (nbits - 1)
|
144
115
|
end
|
145
116
|
end
|
146
117
|
end
|
147
118
|
|
148
119
|
describe "Little endian bitfields" do
|
149
|
-
|
120
|
+
include AllBitfields
|
150
121
|
|
151
|
-
before
|
122
|
+
before do
|
152
123
|
@bits = generate_bit_classes_to_test(:little)
|
153
124
|
end
|
154
125
|
|
@@ -157,7 +128,36 @@ describe "Little endian bitfields" do
|
|
157
128
|
nbytes = (nbits + 7) / 8
|
158
129
|
str = [0b0000_0001].pack("C") + "\000" * (nbytes - 1)
|
159
130
|
|
160
|
-
bit_class.read(str).
|
131
|
+
bit_class.read(str).must_equal 1
|
161
132
|
end
|
162
133
|
end
|
163
134
|
end
|
135
|
+
|
136
|
+
describe "Bits of size 1" do
|
137
|
+
let(:bit_classes) { [BinData::Bit1, BinData::Bit1le] }
|
138
|
+
|
139
|
+
it "accept true as value" do
|
140
|
+
bit_classes.each do |bit_class|
|
141
|
+
obj = bit_class.new
|
142
|
+
obj.assign(true)
|
143
|
+
obj.must_equal 1
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
it "accept false as value" do
|
148
|
+
bit_classes.each do |bit_class|
|
149
|
+
obj = bit_class.new
|
150
|
+
obj.assign(false)
|
151
|
+
obj.must_equal 0
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
it "accept nil as value" do
|
156
|
+
bit_classes.each do |bit_class|
|
157
|
+
obj = bit_class.new
|
158
|
+
obj.assign(nil)
|
159
|
+
obj.must_equal 0
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
data/test/choice_test.rb
ADDED
@@ -0,0 +1,260 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "common"))
|
4
|
+
|
5
|
+
class Chooser
|
6
|
+
attr_accessor :choice
|
7
|
+
end
|
8
|
+
|
9
|
+
class BinData::Choice
|
10
|
+
def set_chooser(chooser)
|
11
|
+
@chooser = chooser
|
12
|
+
end
|
13
|
+
def choice=(s)
|
14
|
+
@chooser.choice = s
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def create_choice(choices, options = {})
|
19
|
+
chooser = Chooser.new
|
20
|
+
params = {:choices => choices, :selection => lambda { chooser.choice } }.merge(options)
|
21
|
+
choice = BinData::Choice.new(params)
|
22
|
+
choice.set_chooser(chooser)
|
23
|
+
choice
|
24
|
+
end
|
25
|
+
|
26
|
+
describe BinData::Choice, "when instantiating" do
|
27
|
+
it "ensures mandatory parameters are supplied" do
|
28
|
+
args = {}
|
29
|
+
lambda { BinData::Choice.new(args) }.must_raise ArgumentError
|
30
|
+
|
31
|
+
args = {:selection => 1}
|
32
|
+
lambda { BinData::Choice.new(args) }.must_raise ArgumentError
|
33
|
+
|
34
|
+
args = {:choices => []}
|
35
|
+
lambda { BinData::Choice.new(args) }.must_raise ArgumentError
|
36
|
+
end
|
37
|
+
|
38
|
+
it "fails when a given type is unknown" do
|
39
|
+
args = {:choices => [:does_not_exist], :selection => 0}
|
40
|
+
lambda { BinData::Choice.new(args) }.must_raise BinData::UnRegisteredTypeError
|
41
|
+
end
|
42
|
+
|
43
|
+
it "fails when a given type is unknown" do
|
44
|
+
args = {:choices => {0 => :does_not_exist}, :selection => 0}
|
45
|
+
lambda { BinData::Choice.new(args) }.must_raise BinData::UnRegisteredTypeError
|
46
|
+
end
|
47
|
+
|
48
|
+
it "fails when :choices Hash has a symbol as key" do
|
49
|
+
args = {:choices => {:a => :example_single}, :selection => 0}
|
50
|
+
lambda { BinData::Choice.new(args) }.must_raise ArgumentError
|
51
|
+
end
|
52
|
+
|
53
|
+
it "fails when :choices Hash has a nil key" do
|
54
|
+
args = {:choices => {nil => :example_single}, :selection => 0}
|
55
|
+
lambda { BinData::Choice.new(args) }.must_raise ArgumentError
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
module ChoiceInitializedWithArrayOrHash
|
60
|
+
def test_can_select_the_choice
|
61
|
+
obj.choice = 3
|
62
|
+
obj.must_equal 30
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_shows_the_current_selection
|
66
|
+
obj.choice = 3
|
67
|
+
obj.selection.must_equal 3
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_forwards_snapshot
|
71
|
+
obj.choice = 3
|
72
|
+
obj.snapshot.must_equal 30
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_can_change_the_choice
|
76
|
+
obj.choice = 3
|
77
|
+
|
78
|
+
obj.choice = 7
|
79
|
+
obj.must_equal 70
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_fails_if_no_choice_has_been_set
|
83
|
+
lambda { obj.to_s }.must_raise IndexError
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_wont_select_an_invalid_choice
|
87
|
+
obj.choice = 99
|
88
|
+
lambda { obj.to_s }.must_raise IndexError
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_wont_select_a_nil_choice
|
92
|
+
obj.choice = 1
|
93
|
+
lambda { obj.to_s }.must_raise IndexError
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_handles_missing_methods_correctly
|
97
|
+
obj.choice = 3
|
98
|
+
|
99
|
+
obj.must_respond_to :value
|
100
|
+
obj.wont_respond_to :does_not_exist
|
101
|
+
lambda { obj.does_not_exist }.must_raise NoMethodError
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_delegates_methods_to_the_selected_single_choice
|
105
|
+
obj.choice = 5
|
106
|
+
obj.num_bytes.must_equal ExampleSingle.new.num_bytes
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe BinData::Choice, "with sparse choices array" do
|
111
|
+
include ChoiceInitializedWithArrayOrHash
|
112
|
+
|
113
|
+
let(:obj) {
|
114
|
+
choices = [nil, nil, nil,
|
115
|
+
[:example_single, {:value => 30}], nil,
|
116
|
+
[:example_single, {:value => 50}], nil,
|
117
|
+
[:example_single, {:value => 70}]]
|
118
|
+
create_choice(choices)
|
119
|
+
}
|
120
|
+
end
|
121
|
+
|
122
|
+
describe BinData::Choice, "with choices hash" do
|
123
|
+
include ChoiceInitializedWithArrayOrHash
|
124
|
+
|
125
|
+
let(:obj) {
|
126
|
+
choices = {3 => [:example_single, {:value => 30}],
|
127
|
+
5 => [:example_single, {:value => 50}],
|
128
|
+
7 => [:example_single, {:value => 70}]}
|
129
|
+
create_choice(choices)
|
130
|
+
}
|
131
|
+
end
|
132
|
+
|
133
|
+
describe BinData::Choice, "with single values" do
|
134
|
+
let(:obj) {
|
135
|
+
choices = {3 => :example_single,
|
136
|
+
5 => :example_single,
|
137
|
+
7 => :example_single}
|
138
|
+
create_choice(choices)
|
139
|
+
}
|
140
|
+
|
141
|
+
it "assigns raw values" do
|
142
|
+
obj.choice = 3
|
143
|
+
obj.assign(254)
|
144
|
+
obj.must_equal 254
|
145
|
+
end
|
146
|
+
|
147
|
+
it "assigns Single values" do
|
148
|
+
data = ExampleSingle.new(11)
|
149
|
+
|
150
|
+
obj.choice = 3
|
151
|
+
obj.assign(data)
|
152
|
+
obj.must_equal 11
|
153
|
+
end
|
154
|
+
|
155
|
+
it "clears" do
|
156
|
+
obj.choice = 3
|
157
|
+
obj.assign(254)
|
158
|
+
|
159
|
+
obj.clear
|
160
|
+
obj.must_equal 0
|
161
|
+
end
|
162
|
+
|
163
|
+
it "clears all possible choices" do
|
164
|
+
obj.choice = 3
|
165
|
+
obj.assign(10)
|
166
|
+
obj.choice = 5
|
167
|
+
obj.assign(11)
|
168
|
+
|
169
|
+
obj.clear
|
170
|
+
|
171
|
+
obj.choice = 3
|
172
|
+
obj.must_equal 0
|
173
|
+
end
|
174
|
+
|
175
|
+
it "is clear on initialisation" do
|
176
|
+
obj.choice = 3
|
177
|
+
|
178
|
+
assert obj.clear?
|
179
|
+
end
|
180
|
+
|
181
|
+
it "is not clear after assignment" do
|
182
|
+
obj.choice = 3
|
183
|
+
obj.assign(254)
|
184
|
+
|
185
|
+
refute obj.clear?
|
186
|
+
end
|
187
|
+
|
188
|
+
it "does not copy value when changing selection" do
|
189
|
+
obj.choice = 3
|
190
|
+
obj.assign(254)
|
191
|
+
|
192
|
+
obj.choice = 7
|
193
|
+
obj.wont_equal 254
|
194
|
+
end
|
195
|
+
|
196
|
+
it "behaves as value" do
|
197
|
+
obj.choice = 3
|
198
|
+
obj.assign(5)
|
199
|
+
|
200
|
+
(obj + 1).must_equal 6
|
201
|
+
(1 + obj).must_equal 6
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
describe BinData::Choice, "with copy_on_change => true" do
|
206
|
+
let(:obj) {
|
207
|
+
choices = {3 => :example_single,
|
208
|
+
5 => :example_single,
|
209
|
+
7 => :example_single}
|
210
|
+
create_choice(choices, :copy_on_change => true)
|
211
|
+
}
|
212
|
+
|
213
|
+
it "copies value when changing selection" do
|
214
|
+
obj.choice = 3
|
215
|
+
obj.assign(254)
|
216
|
+
|
217
|
+
obj.choice = 7
|
218
|
+
obj.must_equal 254
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
describe BinData::Choice, "with :default" do
|
223
|
+
let(:choices) { { "a" => :int8, :default => :int16be } }
|
224
|
+
|
225
|
+
it "selects for existing case" do
|
226
|
+
obj = BinData::Choice.new(:selection => "a", :choices => choices)
|
227
|
+
obj.num_bytes.must_equal 1
|
228
|
+
end
|
229
|
+
|
230
|
+
it "selects for default case" do
|
231
|
+
obj = BinData::Choice.new(:selection => "other", :choices => choices)
|
232
|
+
obj.num_bytes.must_equal 2
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
describe BinData::Choice, "subclassed with default parameters" do
|
237
|
+
class DerivedChoice < BinData::Choice
|
238
|
+
endian :big
|
239
|
+
default_parameter :selection => 'a'
|
240
|
+
|
241
|
+
uint16 'a'
|
242
|
+
uint32 'b'
|
243
|
+
uint64 :default
|
244
|
+
end
|
245
|
+
|
246
|
+
it "sets initial selection" do
|
247
|
+
obj = DerivedChoice.new
|
248
|
+
obj.num_bytes.must_equal 2
|
249
|
+
end
|
250
|
+
|
251
|
+
it "overides default parameter" do
|
252
|
+
obj = DerivedChoice.new(:selection => 'b')
|
253
|
+
obj.num_bytes.must_equal 4
|
254
|
+
end
|
255
|
+
|
256
|
+
it "selects default selection" do
|
257
|
+
obj = DerivedChoice.new(:selection => 'z')
|
258
|
+
obj.num_bytes.must_equal 8
|
259
|
+
end
|
260
|
+
end
|