bindata 1.2.2 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of bindata might be problematic. Click here for more details.

Files changed (52) hide show
  1. data/ChangeLog +12 -0
  2. data/NEWS +53 -0
  3. data/Rakefile +2 -1
  4. data/examples/NBT.txt +149 -0
  5. data/examples/ip_address.rb +1 -2
  6. data/examples/list.rb +124 -0
  7. data/examples/nbt.rb +195 -0
  8. data/lib/bindata.rb +4 -3
  9. data/lib/bindata/alignment.rb +86 -0
  10. data/lib/bindata/array.rb +21 -29
  11. data/lib/bindata/base.rb +82 -81
  12. data/lib/bindata/base_primitive.rb +66 -48
  13. data/lib/bindata/choice.rb +18 -28
  14. data/lib/bindata/deprecated.rb +17 -0
  15. data/lib/bindata/dsl.rb +25 -15
  16. data/lib/bindata/int.rb +2 -2
  17. data/lib/bindata/io.rb +8 -6
  18. data/lib/bindata/offset.rb +91 -0
  19. data/lib/bindata/primitive.rb +22 -11
  20. data/lib/bindata/record.rb +40 -10
  21. data/lib/bindata/sanitize.rb +15 -30
  22. data/lib/bindata/string.rb +16 -17
  23. data/lib/bindata/stringz.rb +0 -1
  24. data/lib/bindata/struct.rb +17 -6
  25. data/lib/bindata/trace.rb +52 -0
  26. data/lib/bindata/wrapper.rb +28 -6
  27. data/manual.haml +56 -10
  28. data/manual.md +318 -113
  29. data/spec/alignment_spec.rb +61 -0
  30. data/spec/array_spec.rb +139 -178
  31. data/spec/base_primitive_spec.rb +86 -111
  32. data/spec/base_spec.rb +200 -172
  33. data/spec/bits_spec.rb +45 -53
  34. data/spec/choice_spec.rb +91 -87
  35. data/spec/deprecated_spec.rb +36 -14
  36. data/spec/float_spec.rb +16 -68
  37. data/spec/int_spec.rb +26 -27
  38. data/spec/io_spec.rb +105 -105
  39. data/spec/lazy_spec.rb +50 -50
  40. data/spec/primitive_spec.rb +36 -36
  41. data/spec/record_spec.rb +134 -134
  42. data/spec/registry_spec.rb +34 -38
  43. data/spec/rest_spec.rb +8 -11
  44. data/spec/skip_spec.rb +9 -17
  45. data/spec/spec_common.rb +4 -0
  46. data/spec/string_spec.rb +92 -115
  47. data/spec/stringz_spec.rb +41 -74
  48. data/spec/struct_spec.rb +132 -153
  49. data/spec/system_spec.rb +115 -60
  50. data/spec/wrapper_spec.rb +63 -31
  51. data/tasks/pkg.rake +1 -1
  52. metadata +15 -7
@@ -5,26 +5,24 @@ require File.expand_path(File.join(File.dirname(__FILE__), "example"))
5
5
  require 'bindata/base_primitive'
6
6
  require 'bindata/io'
7
7
 
8
- describe BinData::BasePrimitive, "when subclassing" do
8
+ describe BinData::BasePrimitive, "all subclasses" do
9
9
  class SubClassOfBasePrimitive < BinData::BasePrimitive
10
10
  expose_methods_for_testing
11
11
  end
12
12
 
13
- before(:each) do
14
- @obj = SubClassOfBasePrimitive.new
15
- end
13
+ subject { SubClassOfBasePrimitive.new }
16
14
 
17
15
  it "should raise errors on unimplemented methods" do
18
- lambda { @obj.value_to_binary_string(nil) }.should raise_error(NotImplementedError)
19
- lambda { @obj.read_and_return_value(nil) }.should raise_error(NotImplementedError)
20
- lambda { @obj.sensible_default }.should raise_error(NotImplementedError)
16
+ lambda { subject.value_to_binary_string(nil) }.should raise_error(NotImplementedError)
17
+ lambda { subject.read_and_return_value(nil) }.should raise_error(NotImplementedError)
18
+ lambda { subject.sensible_default }.should raise_error(NotImplementedError)
21
19
  end
22
20
  end
23
21
 
24
22
  describe BinData::BasePrimitive do
25
23
  it "should conform to rule 1 for returning a value" do
26
24
  data = ExampleSingle.new(:value => 5)
27
- data.value.should == 5
25
+ data.should == 5
28
26
  end
29
27
 
30
28
  it "should conform to rule 2 for returning a value" do
@@ -32,224 +30,201 @@ describe BinData::BasePrimitive do
32
30
  data = ExampleSingle.new(:value => 5)
33
31
  data.read(io)
34
32
 
35
- def data.reading?; true; end
36
- data.value.should == 42
33
+ data.stub(:reading?).and_return(true)
34
+ data.should == 42
37
35
  end
38
36
 
39
37
  it "should conform to rule 3 for returning a value" do
40
38
  data = ExampleSingle.new(:initial_value => 5)
41
39
  data.should be_clear
42
- data.value.should == 5
40
+ data.should == 5
43
41
  end
44
42
 
45
43
  it "should conform to rule 4 for returning a value" do
46
44
  data = ExampleSingle.new(:initial_value => 5)
47
- data.value = 17
45
+ data.assign(17)
48
46
  data.should_not be_clear
49
- data.value.should == 17
47
+ data.should == 17
50
48
  end
51
49
 
52
50
  it "should conform to rule 5 for returning a value" do
53
51
  data = ExampleSingle.new
54
52
  data.should be_clear
55
- data.value.should == 0
53
+ data.should == 0
56
54
  end
57
55
 
58
56
  it "should conform to rule 6 for returning a value" do
59
57
  data = ExampleSingle.new
60
- data.value = 8
58
+ data.assign(8)
61
59
  data.should_not be_clear
62
- data.value.should == 8
60
+ data.should == 8
63
61
  end
64
62
  end
65
63
 
66
64
  describe ExampleSingle do
67
- before(:each) do
68
- @data = ExampleSingle.new
69
- @data.value = 5
70
- end
65
+ subject { ExampleSingle.new(5) }
71
66
 
72
67
  it "should fail when assigning nil values" do
73
- lambda { @data.assign(nil) }.should raise_error(ArgumentError)
68
+ lambda { subject.assign(nil) }.should raise_error(ArgumentError)
74
69
  end
75
70
 
76
71
  it "should allowing setting and retrieving value" do
77
- @data.value = 7
78
- @data.value.should == 7
72
+ subject.assign(7)
73
+ subject.should == 7
79
74
  end
80
75
 
81
76
  it "should allowing setting and retrieving BinData::BasePrimitives" do
82
- obj = ExampleSingle.new
83
- obj.value = 7
84
- @data.value = obj
85
- @data.value.should == 7
77
+ subject.assign(ExampleSingle.new(7))
78
+ subject.should == 7
86
79
  end
87
80
 
88
81
  it "should respond to known methods" do
89
- @data.should respond_to(:num_bytes)
82
+ subject.should respond_to(:num_bytes)
90
83
  end
91
84
 
92
85
  it "should respond to known methods in #snapshot" do
93
- @data.should respond_to(:div)
86
+ subject.should respond_to(:div)
94
87
  end
95
88
 
96
89
  it "should not respond to unknown methods in self or #snapshot" do
97
- @data.should_not respond_to(:does_not_exist)
90
+ subject.should_not respond_to(:does_not_exist)
98
91
  end
99
92
 
100
93
  it "should behave as #snapshot" do
101
- (@data + 1).should == 6
102
- (1 + @data).should == 6
94
+ (subject + 1).should == 6
95
+ (1 + subject).should == 6
103
96
  end
104
97
 
105
98
  it "should be equal to other ExampleSingle" do
106
- other = ExampleSingle.new
107
- other.value = 5
108
- @data.should == other
99
+ subject.should == ExampleSingle.new(5)
109
100
  end
110
101
 
111
102
  it "should be equal to raw values" do
112
- @data.should == 5
113
- 5.should == @data
103
+ subject.should == 5
104
+ 5.should == subject
114
105
  end
115
106
 
116
107
  it "should work as hash keys" do
117
108
  hash = {5 => 17}
118
109
 
119
- obj = ExampleSingle.new
120
- obj.value = 5
110
+ hash[subject].should == 17
111
+ end
121
112
 
122
- hash[obj].should == 17
113
+ it "should be able to sort" do
114
+ [ExampleSingle.new(5), ExampleSingle.new(3)].sort.should == [3, 5]
123
115
  end
124
116
  end
125
117
 
126
118
  describe BinData::BasePrimitive, "after initialisation" do
127
- before(:each) do
128
- @data = ExampleSingle.new
129
- end
119
+ subject { ExampleSingle.new }
130
120
 
131
121
  it "should not allow both :initial_value and :value" do
132
122
  params = {:initial_value => 1, :value => 2}
133
123
  lambda { ExampleSingle.new(params) }.should raise_error(ArgumentError)
134
124
  end
135
125
 
136
- it "should have a sensible value" do
137
- @data.value.should == 0
138
- end
126
+ it { should be_clear }
127
+ its(:value) { should == 0 }
128
+ its(:num_bytes) { should == 4 }
139
129
 
140
130
  it "should have symmetric IO" do
141
- @data.value = 42
142
- written = @data.to_binary_s
131
+ subject.assign(42)
132
+ written = subject.to_binary_s
143
133
 
144
134
  ExampleSingle.read(written).should == 42
145
135
  end
146
136
 
147
137
  it "should allowing setting and retrieving value" do
148
- @data.value = 5
149
- @data.value.should == 5
150
- end
151
-
152
- it "should be clear" do
153
- @data.should be_clear
138
+ subject.value = 5
139
+ subject.value.should == 5
154
140
  end
155
141
 
156
142
  it "should not be clear after setting value" do
157
- @data.value = 5
158
- @data.should_not be_clear
143
+ subject.assign(5)
144
+ subject.should_not be_clear
159
145
  end
160
146
 
161
147
  it "should not be clear after reading" do
162
- @data.read("\x11\x22\x33\x44")
163
- @data.should_not be_clear
164
- end
165
-
166
- it "should return num_bytes" do
167
- @data.num_bytes.should == 4
148
+ subject.read("\x11\x22\x33\x44")
149
+ subject.should_not be_clear
168
150
  end
169
151
 
170
152
  it "should return a snapshot" do
171
- @data.value = 5
172
- @data.snapshot.should == 5
153
+ subject.assign(5)
154
+ subject.snapshot.should == 5
173
155
  end
174
156
  end
175
157
 
176
158
  describe BinData::BasePrimitive, "with :initial_value" do
177
- before(:each) do
178
- @data = ExampleSingle.new(:initial_value => 5)
179
- end
159
+ subject { ExampleSingle.new(:initial_value => 5) }
180
160
 
181
- it "should return that initial value before reading or being set" do
182
- @data.value.should == 5
183
- end
161
+ its(:value) { should == 5 }
184
162
 
185
163
  it "should forget :initial_value after being set" do
186
- @data.value = 17
187
- @data.value.should_not == 5
164
+ subject.assign(17)
165
+ subject.should_not == 5
188
166
  end
189
167
 
190
168
  it "should forget :initial_value after reading" do
191
- @data.read("\x11\x22\x33\x44")
192
- @data.value.should_not == 5
169
+ subject.read("\x11\x22\x33\x44")
170
+ subject.should_not == 5
193
171
  end
194
172
 
195
173
  it "should remember :initial_value after being cleared" do
196
- @data.value = 17
197
- @data.clear
198
- @data.value.should == 5
174
+ subject.assign(17)
175
+ subject.clear
176
+ subject.should == 5
199
177
  end
200
178
  end
201
179
 
202
180
  describe BinData::BasePrimitive, "with :value" do
203
- before(:each) do
204
- @data = ExampleSingle.new(:value => 5)
205
- end
181
+ subject { ExampleSingle.new(:value => 5) }
206
182
 
207
- it "should return that :value" do
208
- @data.value.should == 5
209
- end
183
+ its(:value) { should == 5 }
210
184
 
211
- it "should change during reading" do
212
- io = ExampleSingle.io_with_value(56)
213
- @data.read(io)
185
+ let(:io) { ExampleSingle.io_with_value(56) }
214
186
 
215
- def @data.reading?; true; end
216
- @data.value.should == 56
187
+ it "should change during reading" do
188
+ subject.read(io)
189
+ subject.stub(:reading?).and_return(true)
190
+ subject.should == 56
217
191
  end
218
192
 
219
193
  it "should not change after reading" do
220
- io = ExampleSingle.io_with_value(56)
221
- @data.read(io)
222
- @data.value.should == 5
194
+ subject.read(io)
195
+ subject.should == 5
223
196
  end
224
197
 
225
198
  it "should not be able to change the value" do
226
- @data.value = 17
227
- @data.value.should == 5
199
+ subject.assign(17)
200
+ subject.should == 5
228
201
  end
229
202
  end
230
203
 
231
- describe BinData::BasePrimitive, "with :check_value" do
232
- before(:each) do
233
- @io = ExampleSingle.io_with_value(34)
234
- end
204
+ describe BinData::BasePrimitive, "checking read value" do
205
+ let(:io) { ExampleSingle.io_with_value(12) }
235
206
 
236
- it "should succeed when check_value is non boolean and correct" do
237
- data = ExampleSingle.new(:check_value => 34)
238
- lambda { data.read(@io) }.should_not raise_error
239
- end
207
+ context ":check_value is non boolean" do
208
+ it "should succeed when check_value and correct" do
209
+ data = ExampleSingle.new(:check_value => 12)
210
+ lambda { data.read(io) }.should_not raise_error
211
+ end
240
212
 
241
- it "should fail when check_value is non boolean and incorrect" do
242
- data = ExampleSingle.new(:check_value => lambda { 123 * 5 })
243
- lambda { data.read(@io) }.should raise_error(BinData::ValidityError)
213
+ it "should fail when check_value is incorrect" do
214
+ data = ExampleSingle.new(:check_value => lambda { 99 })
215
+ lambda { data.read(io) }.should raise_error(BinData::ValidityError)
216
+ end
244
217
  end
245
218
 
246
- it "should succeed when check_value is boolean and true" do
247
- data = ExampleSingle.new(:check_value => lambda { (value % 2) == 0})
248
- lambda { data.read(@io) }.should_not raise_error
249
- end
219
+ context ":check_value is boolean" do
220
+ it "should succeed when check_value is true" do
221
+ data = ExampleSingle.new(:check_value => lambda { value < 20 })
222
+ lambda { data.read(io) }.should_not raise_error
223
+ end
250
224
 
251
- it "should fail when check_value is boolean and false" do
252
- data = ExampleSingle.new(:check_value => lambda { value > 100 })
253
- lambda { data.read(@io) }.should raise_error(BinData::ValidityError)
225
+ it "should fail when check_value is false" do
226
+ data = ExampleSingle.new(:check_value => lambda { value > 20 })
227
+ lambda { data.read(io) }.should raise_error(BinData::ValidityError)
228
+ end
254
229
  end
255
230
  end
@@ -7,49 +7,32 @@ class BaseStub < BinData::Base
7
7
  # Override to avoid NotImplemented errors
8
8
  def clear; end
9
9
  def clear?; end
10
- def assign(x); end
11
- def snapshot; end
10
+ def assign(x); @data = x; end
11
+ def snapshot; @data; end
12
12
  def do_read(io) end
13
13
  def do_write(io) end
14
14
  def do_num_bytes; end
15
15
  end
16
16
 
17
- class MockBaseStub < BaseStub
18
- attr_accessor :mock
19
- def clear; mock.clear; end
20
- def clear?; mock.clear?; end
21
- def assign(x); mock.assign(x); end
22
- def snapshot; mock.snapshot; end
23
- def do_read(io) mock.do_read(io); end
24
- def do_write(io) mock.do_write(io); end
25
- def do_num_bytes; mock.do_num_bytes; end
26
- end
27
-
28
- describe BinData::Base, "when subclassing" do
17
+ describe BinData::Base, "all subclasses" do
29
18
  class SubClassOfBase < BinData::Base
30
19
  expose_methods_for_testing
31
20
  end
32
21
 
33
- before(:each) do
34
- @obj = SubClassOfBase.new
35
- end
22
+ subject { SubClassOfBase.new }
36
23
 
37
24
  it "should raise errors on unimplemented methods" do
38
- lambda { @obj.clear }.should raise_error(NotImplementedError)
39
- lambda { @obj.clear? }.should raise_error(NotImplementedError)
40
- lambda { @obj.assign(nil) }.should raise_error(NotImplementedError)
41
- lambda { @obj.snapshot }.should raise_error(NotImplementedError)
42
- lambda { @obj.do_read(nil) }.should raise_error(NotImplementedError)
43
- lambda { @obj.do_write(nil) }.should raise_error(NotImplementedError)
44
- lambda { @obj.do_num_bytes }.should raise_error(NotImplementedError)
25
+ lambda { subject.clear }.should raise_error(NotImplementedError)
26
+ lambda { subject.clear? }.should raise_error(NotImplementedError)
27
+ lambda { subject.assign(nil) }.should raise_error(NotImplementedError)
28
+ lambda { subject.snapshot }.should raise_error(NotImplementedError)
29
+ lambda { subject.do_read(nil) }.should raise_error(NotImplementedError)
30
+ lambda { subject.do_write(nil) }.should raise_error(NotImplementedError)
31
+ lambda { subject.do_num_bytes }.should raise_error(NotImplementedError)
45
32
  end
46
33
  end
47
34
 
48
35
  describe BinData::Base, "with parameters" do
49
- it "should raise error if parameter has nil value" do
50
- lambda { BaseStub.new(:a => nil) }.should raise_error(ArgumentError)
51
- end
52
-
53
36
  it "should raise error if parameter name is invalid" do
54
37
  lambda {
55
38
  class InvalidParameterNameBase < BinData::Base
@@ -58,10 +41,13 @@ describe BinData::Base, "with parameters" do
58
41
  }.should raise_error(NameError)
59
42
  end
60
43
 
61
- it "should convert keys to symbols" do
62
- obj = BaseStub.new('a' => 3)
63
- obj.should have_parameter(:a)
64
- obj.get_parameter(:a).should == 3
44
+ it "should raise error if parameter has nil value" do
45
+ lambda { BaseStub.new(:a => nil) }.should raise_error(ArgumentError)
46
+ end
47
+
48
+ it "should convert parameter keys to symbols" do
49
+ subject = BaseStub.new('a' => 3)
50
+ subject.should have_parameter(:a)
65
51
  end
66
52
  end
67
53
 
@@ -92,15 +78,13 @@ describe BinData::Base, "with default parameters" do
92
78
  end
93
79
 
94
80
  it "should use default parameters when not specified" do
95
- obj = DefaultBase.new
96
- obj.should have_parameter(:p1)
97
- obj.eval_parameter(:p1).should == "a"
81
+ subject = DefaultBase.new
82
+ subject.eval_parameter(:p1).should == "a"
98
83
  end
99
84
 
100
85
  it "should be able to override default parameters" do
101
- obj = DefaultBase.new(:p1 => "b")
102
- obj.should have_parameter(:p1)
103
- obj.eval_parameter(:p1).should == "b"
86
+ subject = DefaultBase.new(:p1 => "b")
87
+ subject.eval_parameter(:p1).should == "b"
104
88
  end
105
89
  end
106
90
 
@@ -127,8 +111,8 @@ end
127
111
  describe BinData::Base, "with multiple parameters" do
128
112
  class WithParamBase < BaseStub
129
113
  mandatory_parameter :p1
130
- optional_parameter :p2
131
- default_parameter :p3 => 3
114
+ default_parameter :p2 => 2
115
+ optional_parameter :p3
132
116
  end
133
117
 
134
118
  it "should identify internally accepted parameters" do
@@ -139,124 +123,110 @@ describe BinData::Base, "with multiple parameters" do
139
123
  accepted.should_not include(:xx)
140
124
  end
141
125
 
142
- it "should evaluate parameters" do
143
- params = {:p1 => 1, :p2 => 2, :p3 => 3, :p4 => lambda { 4 }}
144
- obj = WithParamBase.new(params)
145
- obj.eval_parameter(:p4).should == 4
146
- end
126
+ context "examining parameters" do
127
+ subject {
128
+ params = {:p1 => 1, :p3 => :xx, :p4 => lambda { 4 }}
129
+ WithParamBase.new(params)
130
+ }
147
131
 
148
- it "should return parameters" do
149
- params = {:p1 => 1, :p2 => 2, :p3 => 3, :p4 => :a}
150
- obj = WithParamBase.new(params)
151
- obj.get_parameter(:p4).should == :a
152
- end
153
-
154
- it "should have parameters" do
155
- params = {:p1 => 1, :p2 => 2, :p3 => 3, :p4 => 4}
156
- obj = WithParamBase.new(params)
157
- obj.should have_parameter(:p4)
158
- end
132
+ it "should evaluate parameters" do
133
+ subject.eval_parameter(:p1).should == 1
134
+ subject.eval_parameter(:p2).should == 2
135
+ lambda { subject.eval_parameter(:p3) }.should raise_error(NoMethodError)
136
+ subject.eval_parameter(:p4).should == 4
137
+ end
159
138
 
160
- it "should not allow parameters with nil values" do
161
- lambda { WithParamBase.new(:p1 => 1, :p2 => nil) }.should raise_error(ArgumentError)
162
- end
139
+ it "should get parameters without evaluating" do
140
+ subject.get_parameter(:p1).should == 1
141
+ subject.get_parameter(:p2).should == 2
142
+ subject.get_parameter(:p3).should == :xx
143
+ subject.get_parameter(:p4).should respond_to(:arity)
144
+ end
163
145
 
164
- it "should be able to access without evaluating" do
165
- obj = WithParamBase.new(:p1 => :asym, :p3 => lambda {1 + 2})
166
- obj.get_parameter(:p1).should == :asym
167
- obj.get_parameter(:p2).should be_nil
168
- obj.get_parameter(:p3).should respond_to(:arity)
146
+ it "should have parameters" do
147
+ subject.should have_parameter(:p1)
148
+ subject.should have_parameter(:p2)
149
+ subject.should have_parameter(:p3)
150
+ subject.should have_parameter(:p4)
151
+ end
169
152
  end
170
153
  end
171
154
 
172
- describe BinData::Base, "with :check_offset" do
173
- class TenByteOffsetBase < BaseStub
174
- def initialize(params = {})
175
- super({})
176
- @child = BaseStub.new(params, self)
155
+ describe BinData::Base, "when initializing" do
156
+ class BaseInit < BaseStub
157
+ class << self
158
+ attr_accessor :calls
159
+ def recorded_calls(&block)
160
+ self.calls = []
161
+ block.call
162
+ calls
163
+ end
177
164
  end
178
165
 
179
- def do_read(io)
180
- io.seekbytes(10)
181
- @child.do_read(io)
166
+ def initialize_instance
167
+ self.class.calls << :initialize_instance
182
168
  end
183
- end
184
-
185
- before(:each) do
186
- @io = StringIO.new("12345678901234567890")
187
- end
188
-
189
- it "should fail if offset is incorrect" do
190
- @io.seek(2)
191
- obj = TenByteOffsetBase.new(:check_offset => 8)
192
- lambda { obj.read(@io) }.should raise_error(BinData::ValidityError)
193
- end
194
169
 
195
- it "should succeed if offset is correct" do
196
- @io.seek(3)
197
- obj = TenByteOffsetBase.new(:check_offset => 10)
198
- lambda { obj.read(@io) }.should_not raise_error
170
+ def initialize_shared_instance
171
+ self.class.calls << :initialize_shared_instance
172
+ end
199
173
  end
200
174
 
201
- it "should fail if :check_offset fails" do
202
- @io.seek(4)
203
- obj = TenByteOffsetBase.new(:check_offset => lambda { offset == 11 } )
204
- lambda { obj.read(@io) }.should raise_error(BinData::ValidityError)
175
+ it "should call both #initialize_xxx methods when initializing" do
176
+ BaseInit.recorded_calls {
177
+ BaseInit.new
178
+ }.should == [:initialize_shared_instance, :initialize_instance]
205
179
  end
206
180
 
207
- it "should succeed if :check_offset succeeds" do
208
- @io.seek(5)
209
- obj = TenByteOffsetBase.new(:check_offset => lambda { offset == 10 } )
210
- lambda { obj.read(@io) }.should_not raise_error
211
- end
212
- end
181
+ context "as a factory" do
182
+ subject { BaseInit.new(:check_offset => 1) }
213
183
 
214
- describe BinData::Base, "with :adjust_offset" do
215
- class TenByteAdjustingOffsetBase < BaseStub
216
- def initialize(params = {})
217
- super({})
218
- @child = BaseStub.new(params, self)
219
- end
184
+ describe "#new" do
185
+ it "should call #initialize_instance" do
186
+ obj = subject
220
187
 
221
- def do_read(io)
222
- io.seekbytes(10)
223
- @child.do_read(io)
224
- end
225
- end
188
+ BaseInit.recorded_calls {
189
+ obj.new
190
+ }.should == [:initialize_instance]
191
+ end
226
192
 
227
- before(:each) do
228
- @io = StringIO.new("12345678901234567890")
229
- end
193
+ it "should copy parameters" do
194
+ obj = subject.new
195
+ obj.eval_parameter(:check_offset).should == 1
196
+ end
230
197
 
231
- it "should be mutually exclusive with :check_offset" do
232
- params = { :check_offset => 8, :adjust_offset => 8 }
233
- lambda { TenByteAdjustingOffsetBase.new(params) }.should raise_error(ArgumentError)
234
- end
198
+ it "should perform action for :check_offset" do
199
+ obj = subject.new
200
+ lambda {
201
+ obj.read("abc")
202
+ }.should raise_error(BinData::ValidityError)
203
+ end
235
204
 
236
- it "should adjust if offset is incorrect" do
237
- @io.seek(2)
238
- obj = TenByteAdjustingOffsetBase.new(:adjust_offset => 13)
239
- obj.read(@io)
240
- @io.pos.should == (2 + 13)
241
- end
205
+ it "should assign value" do
206
+ obj = subject.new(3)
207
+ obj.snapshot.should == 3
208
+ end
242
209
 
243
- it "should succeed if offset is correct" do
244
- @io.seek(3)
245
- obj = TenByteAdjustingOffsetBase.new(:adjust_offset => 10)
246
- lambda { obj.read(@io) }.should_not raise_error
247
- @io.pos.should == (3 + 10)
210
+ it "should set parent" do
211
+ obj = subject.new(3, "p")
212
+ obj.parent.should == "p"
213
+ end
214
+ end
248
215
  end
216
+ end
249
217
 
250
- it "should fail if cannot adjust offset" do
251
- @io.seek(3)
252
- obj = TenByteAdjustingOffsetBase.new(:adjust_offset => -4)
253
- lambda { obj.read(@io) }.should raise_error(BinData::ValidityError)
254
- end
218
+ describe BinData::Base, "as a factory" do
255
219
  end
256
220
 
257
221
  describe BinData::Base, "as black box" do
258
- it "should return bindata_name" do
259
- BaseStub.bindata_name.should == "base_stub"
222
+ context "class methods" do
223
+ it "should return bindata_name" do
224
+ BaseStub.bindata_name.should == "base_stub"
225
+ end
226
+
227
+ it "should instantiate self for ::read" do
228
+ BaseStub.read("").class.should == BaseStub
229
+ end
260
230
  end
261
231
 
262
232
  it "should access parent" do
@@ -265,47 +235,34 @@ describe BinData::Base, "as black box" do
265
235
  child.parent.should == parent
266
236
  end
267
237
 
268
- it "should instantiate self for ::read" do
269
- BaseStub.read("").class.should == BaseStub
270
- end
238
+ subject { BaseStub.new }
271
239
 
272
240
  it "should return self for #read" do
273
- obj = BaseStub.new
274
- obj.read("").should == obj
241
+ subject.read("").should == subject
275
242
  end
276
243
 
277
244
  it "should return self for #write" do
278
- obj = BaseStub.new
279
- obj.write("").should == obj
245
+ subject.write("").should == subject
280
246
  end
281
247
 
282
248
  it "should forward #inspect to snapshot" do
283
- class SnapshotBase < BaseStub
284
- def snapshot; [1, 2, 3]; end
285
- end
286
- obj = SnapshotBase.new
287
- obj.inspect.should == obj.snapshot.inspect
249
+ subject.stub(:snapshot).and_return([1, 2, 3])
250
+ subject.inspect.should == subject.snapshot.inspect
288
251
  end
289
252
 
290
253
  it "should forward #to_s to snapshot" do
291
- class SnapshotBase < BaseStub
292
- def snapshot; [1, 2, 3]; end
293
- end
294
- obj = SnapshotBase.new
295
- obj.to_s.should == obj.snapshot.to_s
254
+ subject.stub(:snapshot).and_return([1, 2, 3])
255
+ subject.to_s.should == subject.snapshot.to_s
296
256
  end
297
257
 
298
258
  it "should pretty print object as snapshot" do
299
- class SnapshotBase < BaseStub
300
- def snapshot; [1, 2, 3]; end
301
- end
302
- obj = SnapshotBase.new
259
+ subject.stub(:snapshot).and_return([1, 2, 3])
303
260
  actual_io = StringIO.new
304
261
  expected_io = StringIO.new
305
262
 
306
263
  require 'pp'
307
- PP.pp(obj, actual_io)
308
- PP.pp(obj.snapshot, expected_io)
264
+ PP.pp(subject, actual_io)
265
+ PP.pp(subject.snapshot, expected_io)
309
266
 
310
267
  actual_io.value.should == expected_io.value
311
268
  end
@@ -315,37 +272,108 @@ describe BinData::Base, "as black box" do
315
272
  def do_write(io) io.writebytes("abc"); end
316
273
  end
317
274
 
318
- obj = WriteToSBase.new
275
+ subject = WriteToSBase.new
319
276
  io = StringIO.new
320
- obj.write(io)
321
- io.value.should == obj.to_binary_s
277
+ subject.write(io)
278
+ io.value.should == subject.to_binary_s
322
279
  end
323
280
  end
324
281
 
325
282
  describe BinData::Base, "as white box" do
326
- before(:each) do
327
- @obj = MockBaseStub.new
328
- @obj.mock = mock('mock')
329
- end
283
+ subject { BaseStub.new }
330
284
 
331
285
  it "should forward read to do_read" do
332
- @obj.mock.should_receive(:clear).ordered
333
- @obj.mock.should_receive(:do_read).ordered
334
- @obj.read(nil)
286
+ subject.should_receive(:clear).ordered
287
+ subject.should_receive(:do_read).ordered
288
+ subject.read(nil)
335
289
  end
336
290
 
337
291
  it "should forward write to do_write" do
338
- @obj.mock.should_receive(:do_write)
339
- @obj.write(nil)
292
+ subject.should_receive(:do_write)
293
+ subject.write(nil)
340
294
  end
341
295
 
342
296
  it "should forward num_bytes to do_num_bytes" do
343
- @obj.mock.should_receive(:do_num_bytes).and_return(42)
344
- @obj.num_bytes.should == 42
297
+ subject.should_receive(:do_num_bytes).and_return(42)
298
+ subject.num_bytes.should == 42
345
299
  end
346
300
 
347
301
  it "should round up fractional num_bytes" do
348
- @obj.mock.should_receive(:do_num_bytes).and_return(42.1)
349
- @obj.num_bytes.should == 43
302
+ subject.should_receive(:do_num_bytes).and_return(42.1)
303
+ subject.num_bytes.should == 43
304
+ end
305
+ end
306
+
307
+ describe BinData::Base, "checking offsets" do
308
+ class TenByteOffsetBase < BaseStub
309
+ def self.create(params)
310
+ obj = self.new
311
+ obj.initialize_child(params)
312
+ obj
313
+ end
314
+
315
+ def initialize_child(params)
316
+ @child = BaseStub.new(params, self)
317
+ end
318
+
319
+ def do_read(io)
320
+ io.seekbytes(10)
321
+ @child.do_read(io)
322
+ end
323
+ end
324
+
325
+ let(:io) { StringIO.new("12345678901234567890") }
326
+
327
+ context "with :check_offset" do
328
+ it "should fail if offset is incorrect" do
329
+ io.seek(2)
330
+ subject = TenByteOffsetBase.create(:check_offset => 8)
331
+ lambda { subject.read(io) }.should raise_error(BinData::ValidityError)
332
+ end
333
+
334
+ it "should succeed if offset is correct" do
335
+ io.seek(3)
336
+ subject = TenByteOffsetBase.create(:check_offset => 10)
337
+ lambda { subject.read(io) }.should_not raise_error
338
+ end
339
+
340
+ it "should fail if :check_offset fails" do
341
+ io.seek(4)
342
+ subject = TenByteOffsetBase.create(:check_offset => lambda { offset == 11 } )
343
+ lambda { subject.read(io) }.should raise_error(BinData::ValidityError)
344
+ end
345
+
346
+ it "should succeed if :check_offset succeeds" do
347
+ io.seek(5)
348
+ subject = TenByteOffsetBase.create(:check_offset => lambda { offset == 10 } )
349
+ lambda { subject.read(io) }.should_not raise_error
350
+ end
351
+ end
352
+
353
+ context "with :adjust_offset" do
354
+ it "should be mutually exclusive with :check_offset" do
355
+ params = { :check_offset => 8, :adjust_offset => 8 }
356
+ lambda { TenByteOffsetBase.create(params) }.should raise_error(ArgumentError)
357
+ end
358
+
359
+ it "should adjust if offset is incorrect" do
360
+ io.seek(2)
361
+ subject = TenByteOffsetBase.create(:adjust_offset => 13)
362
+ subject.read(io)
363
+ io.pos.should == (2 + 13)
364
+ end
365
+
366
+ it "should succeed if offset is correct" do
367
+ io.seek(3)
368
+ subject = TenByteOffsetBase.create(:adjust_offset => 10)
369
+ lambda { subject.read(io) }.should_not raise_error
370
+ io.pos.should == (3 + 10)
371
+ end
372
+
373
+ it "should fail if cannot adjust offset" do
374
+ io.seek(4)
375
+ subject = TenByteOffsetBase.create(:adjust_offset => -5)
376
+ lambda { subject.read(io) }.should raise_error(BinData::ValidityError)
377
+ end
350
378
  end
351
379
  end