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.
- data/ChangeLog +12 -0
- data/NEWS +53 -0
- data/Rakefile +2 -1
- data/examples/NBT.txt +149 -0
- data/examples/ip_address.rb +1 -2
- data/examples/list.rb +124 -0
- data/examples/nbt.rb +195 -0
- data/lib/bindata.rb +4 -3
- data/lib/bindata/alignment.rb +86 -0
- data/lib/bindata/array.rb +21 -29
- data/lib/bindata/base.rb +82 -81
- data/lib/bindata/base_primitive.rb +66 -48
- data/lib/bindata/choice.rb +18 -28
- data/lib/bindata/deprecated.rb +17 -0
- data/lib/bindata/dsl.rb +25 -15
- data/lib/bindata/int.rb +2 -2
- data/lib/bindata/io.rb +8 -6
- data/lib/bindata/offset.rb +91 -0
- data/lib/bindata/primitive.rb +22 -11
- data/lib/bindata/record.rb +40 -10
- data/lib/bindata/sanitize.rb +15 -30
- data/lib/bindata/string.rb +16 -17
- data/lib/bindata/stringz.rb +0 -1
- data/lib/bindata/struct.rb +17 -6
- data/lib/bindata/trace.rb +52 -0
- data/lib/bindata/wrapper.rb +28 -6
- data/manual.haml +56 -10
- data/manual.md +318 -113
- data/spec/alignment_spec.rb +61 -0
- data/spec/array_spec.rb +139 -178
- data/spec/base_primitive_spec.rb +86 -111
- data/spec/base_spec.rb +200 -172
- data/spec/bits_spec.rb +45 -53
- data/spec/choice_spec.rb +91 -87
- data/spec/deprecated_spec.rb +36 -14
- data/spec/float_spec.rb +16 -68
- data/spec/int_spec.rb +26 -27
- data/spec/io_spec.rb +105 -105
- data/spec/lazy_spec.rb +50 -50
- data/spec/primitive_spec.rb +36 -36
- data/spec/record_spec.rb +134 -134
- data/spec/registry_spec.rb +34 -38
- data/spec/rest_spec.rb +8 -11
- data/spec/skip_spec.rb +9 -17
- data/spec/spec_common.rb +4 -0
- data/spec/string_spec.rb +92 -115
- data/spec/stringz_spec.rb +41 -74
- data/spec/struct_spec.rb +132 -153
- data/spec/system_spec.rb +115 -60
- data/spec/wrapper_spec.rb +63 -31
- data/tasks/pkg.rake +1 -1
- metadata +15 -7
data/spec/stringz_spec.rb
CHANGED
@@ -4,148 +4,115 @@ require File.expand_path(File.join(File.dirname(__FILE__), "spec_common"))
|
|
4
4
|
require 'bindata/stringz'
|
5
5
|
|
6
6
|
describe BinData::Stringz, "when empty" do
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
it "should include the zero byte in num_bytes total" do
|
12
|
-
@str.num_bytes.should == 1
|
13
|
-
end
|
14
|
-
|
15
|
-
it "should not append the zero byte terminator to the value" do
|
16
|
-
@str.value.should == ""
|
17
|
-
end
|
18
|
-
|
19
|
-
it "should write the zero byte terminator" do
|
20
|
-
@str.to_binary_s.should == "\0"
|
21
|
-
end
|
7
|
+
its(:value) { should == "" }
|
8
|
+
its(:num_bytes) { should == 1 }
|
9
|
+
its(:to_binary_s) { should == "\0" }
|
22
10
|
end
|
23
11
|
|
24
12
|
describe BinData::Stringz, "with value set" do
|
25
|
-
|
26
|
-
@str = BinData::Stringz.new
|
27
|
-
@str.value = "abcd"
|
28
|
-
end
|
29
|
-
|
30
|
-
it "should include the zero byte in num_bytes total" do
|
31
|
-
@str.num_bytes.should == 5
|
32
|
-
end
|
13
|
+
subject { BinData::Stringz.new("abcd") }
|
33
14
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
it "should write the zero byte terminator" do
|
39
|
-
@str.to_binary_s.should == "abcd\0"
|
40
|
-
end
|
15
|
+
its(:value) { should == "abcd" }
|
16
|
+
its(:num_bytes) { should == 5 }
|
17
|
+
its(:to_binary_s) { should == "abcd\0" }
|
41
18
|
end
|
42
19
|
|
43
20
|
describe BinData::Stringz, "when reading" do
|
44
|
-
before(:each) do
|
45
|
-
@str = BinData::Stringz.new
|
46
|
-
end
|
47
|
-
|
48
21
|
it "should stop at the first zero byte" do
|
49
22
|
io = StringIO.new("abcd\0xyz\0")
|
50
|
-
|
51
|
-
@str.value.should == "abcd"
|
23
|
+
subject.read(io)
|
52
24
|
io.pos.should == 5
|
25
|
+
subject.should == "abcd"
|
53
26
|
end
|
54
27
|
|
55
28
|
it "should handle a zero length string" do
|
56
29
|
io = StringIO.new("\0abcd")
|
57
|
-
|
58
|
-
@str.value.should == ""
|
30
|
+
subject.read(io)
|
59
31
|
io.pos.should == 1
|
32
|
+
subject.should == ""
|
60
33
|
end
|
61
34
|
|
62
35
|
it "should fail if no zero byte is found" do
|
63
|
-
lambda {
|
36
|
+
lambda {subject.read("abcd") }.should raise_error(EOFError)
|
64
37
|
end
|
65
38
|
end
|
66
39
|
|
67
40
|
describe BinData::Stringz, "when setting the value" do
|
68
|
-
before(:each) do
|
69
|
-
@str = BinData::Stringz.new
|
70
|
-
end
|
71
|
-
|
72
41
|
it "should include the zero byte in num_bytes total" do
|
73
|
-
|
74
|
-
|
42
|
+
subject.assign("abcd")
|
43
|
+
subject.num_bytes.should == 5
|
75
44
|
end
|
76
45
|
|
77
46
|
it "should accept empty strings" do
|
78
|
-
|
79
|
-
|
47
|
+
subject.assign("")
|
48
|
+
subject.should == ""
|
80
49
|
end
|
81
50
|
|
82
51
|
it "should accept strings that aren't zero terminated" do
|
83
|
-
|
84
|
-
|
52
|
+
subject.assign("abcd")
|
53
|
+
subject.should == "abcd"
|
85
54
|
end
|
86
55
|
|
87
56
|
it "should accept strings that are zero terminated" do
|
88
|
-
|
89
|
-
|
57
|
+
subject.assign("abcd\0")
|
58
|
+
subject.should == "abcd"
|
90
59
|
end
|
91
60
|
|
92
61
|
it "should accept up to the first zero byte" do
|
93
|
-
|
94
|
-
|
62
|
+
subject.assign("abcd\0xyz\0")
|
63
|
+
subject.should == "abcd"
|
95
64
|
end
|
96
65
|
end
|
97
66
|
|
98
67
|
describe BinData::Stringz, "with max_length" do
|
99
|
-
|
100
|
-
@str = BinData::Stringz.new(:max_length => 5)
|
101
|
-
end
|
68
|
+
subject { BinData::Stringz.new(:max_length => 5) }
|
102
69
|
|
103
70
|
it "should read less than max_length" do
|
104
71
|
io = StringIO.new("abc\0xyz")
|
105
|
-
|
106
|
-
|
72
|
+
subject.read(io)
|
73
|
+
subject.should == "abc"
|
107
74
|
end
|
108
75
|
|
109
76
|
it "should read exactly max_length" do
|
110
77
|
io = StringIO.new("abcd\0xyz")
|
111
|
-
|
112
|
-
|
78
|
+
subject.read(io)
|
79
|
+
subject.should == "abcd"
|
113
80
|
end
|
114
81
|
|
115
82
|
it "should read no more than max_length" do
|
116
83
|
io = StringIO.new("abcdefg\0xyz")
|
117
|
-
|
118
|
-
@str.value.should == "abcd"
|
84
|
+
subject.read(io)
|
119
85
|
io.pos.should == 5
|
86
|
+
subject.should == "abcd"
|
120
87
|
end
|
121
88
|
|
122
89
|
it "should accept values less than max_length" do
|
123
|
-
|
124
|
-
|
90
|
+
subject.assign("abc")
|
91
|
+
subject.should == "abc"
|
125
92
|
end
|
126
93
|
|
127
94
|
it "should accept values exactly max_length" do
|
128
|
-
|
129
|
-
|
95
|
+
subject.assign("abcd")
|
96
|
+
subject.should == "abcd"
|
130
97
|
end
|
131
98
|
|
132
99
|
it "should trim values greater than max_length" do
|
133
|
-
|
134
|
-
|
100
|
+
subject.assign("abcde")
|
101
|
+
subject.should == "abcd"
|
135
102
|
end
|
136
103
|
|
137
104
|
it "should write values greater than max_length" do
|
138
|
-
|
139
|
-
|
105
|
+
subject.assign("abcde")
|
106
|
+
subject.to_binary_s.should == "abcd\0"
|
140
107
|
end
|
141
108
|
|
142
109
|
it "should write values less than max_length" do
|
143
|
-
|
144
|
-
|
110
|
+
subject.assign("abc")
|
111
|
+
subject.to_binary_s.should == "abc\0"
|
145
112
|
end
|
146
113
|
|
147
114
|
it "should write values exactly max_length" do
|
148
|
-
|
149
|
-
|
115
|
+
subject.assign("abcd")
|
116
|
+
subject.to_binary_s.should == "abcd\0"
|
150
117
|
end
|
151
118
|
end
|
data/spec/struct_spec.rb
CHANGED
@@ -42,72 +42,71 @@ describe BinData::Struct, "when initializing" do
|
|
42
42
|
end
|
43
43
|
|
44
44
|
describe BinData::Struct, "with anonymous fields" do
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
45
|
+
subject {
|
46
|
+
params = { :fields => [
|
47
|
+
[:int8, :a, {:initial_value => 5}],
|
48
|
+
[:int8, nil],
|
49
|
+
[:int8, '', {:value => :a}]
|
50
|
+
] }
|
51
|
+
BinData::Struct.new(params)
|
52
|
+
}
|
52
53
|
|
53
54
|
it "should only show non anonymous fields" do
|
54
|
-
|
55
|
+
subject.field_names.should == ["a"]
|
55
56
|
end
|
56
57
|
|
57
58
|
it "should not include anonymous fields in snapshot" do
|
58
|
-
|
59
|
-
|
59
|
+
subject.a = 5
|
60
|
+
subject.snapshot.should == {"a" => 5}
|
60
61
|
end
|
61
62
|
|
62
63
|
it "should write anonymous fields" do
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
@obj.to_binary_s.should == "\012\002\012"
|
64
|
+
subject.read("\001\002\003")
|
65
|
+
subject.a.clear
|
66
|
+
subject.to_binary_s.should == "\005\002\005"
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
70
|
describe BinData::Struct, "with hidden fields" do
|
71
|
-
|
72
|
-
|
73
|
-
|
71
|
+
subject {
|
72
|
+
params = { :hide => [:b, :c],
|
73
|
+
:fields => [
|
74
74
|
[:int8, :a],
|
75
|
-
[:int8, 'b', {:initial_value =>
|
75
|
+
[:int8, 'b', {:initial_value => 5}],
|
76
76
|
[:int8, :c],
|
77
77
|
[:int8, :d, {:value => :b}]] }
|
78
|
-
|
79
|
-
|
78
|
+
BinData::Struct.new(params)
|
79
|
+
}
|
80
80
|
|
81
81
|
it "should only show fields that aren't hidden" do
|
82
|
-
|
82
|
+
subject.field_names.should == ["a", "d"]
|
83
83
|
end
|
84
84
|
|
85
85
|
it "should be able to access hidden fields directly" do
|
86
|
-
|
87
|
-
|
88
|
-
|
86
|
+
subject.b.should == 5
|
87
|
+
subject.c = 15
|
88
|
+
subject.c.should == 15
|
89
89
|
|
90
|
-
|
90
|
+
subject.should respond_to(:b=)
|
91
91
|
end
|
92
92
|
|
93
93
|
it "should not include hidden fields in snapshot" do
|
94
|
-
|
95
|
-
|
94
|
+
subject.b = 7
|
95
|
+
subject.snapshot.should == {"a" => 0, "d" => 7}
|
96
96
|
end
|
97
97
|
end
|
98
98
|
|
99
99
|
describe BinData::Struct, "with multiple fields" do
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
end
|
100
|
+
let(:params) { { :fields => [ [:int8, :a], [:int8, :b] ] } }
|
101
|
+
subject { BinData::Struct.new({:a => 1, :b => 2}, params) }
|
102
|
+
|
103
|
+
its(:field_names) { should == ["a", "b"] }
|
104
|
+
its(:to_binary_s) { should == "\x01\x02" }
|
106
105
|
|
107
106
|
it "should return num_bytes" do
|
108
|
-
|
109
|
-
|
110
|
-
|
107
|
+
subject.a.num_bytes.should == 1
|
108
|
+
subject.b.num_bytes.should == 1
|
109
|
+
subject.num_bytes.should == 2
|
111
110
|
end
|
112
111
|
|
113
112
|
it "should identify accepted parameters" do
|
@@ -116,194 +115,174 @@ describe BinData::Struct, "with multiple fields" do
|
|
116
115
|
BinData::Struct.accepted_parameters.all.should include(:endian)
|
117
116
|
end
|
118
117
|
|
119
|
-
it "should return field names" do
|
120
|
-
@obj.field_names.should == ["a", "b"]
|
121
|
-
end
|
122
|
-
|
123
118
|
it "should clear" do
|
124
|
-
|
125
|
-
|
126
|
-
|
119
|
+
subject.a = 6
|
120
|
+
subject.clear
|
121
|
+
subject.should be_clear
|
127
122
|
end
|
128
123
|
|
129
124
|
it "should clear individual elements" do
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
end
|
136
|
-
|
137
|
-
it "should write ordered" do
|
138
|
-
@obj.to_binary_s.should == "\x01\x02"
|
125
|
+
subject.a = 6
|
126
|
+
subject.b = 7
|
127
|
+
subject.a.clear
|
128
|
+
subject.a.should be_clear
|
129
|
+
subject.b.should_not be_clear
|
139
130
|
end
|
140
131
|
|
141
132
|
it "should read ordered" do
|
142
|
-
|
133
|
+
subject.read("\x03\x04")
|
143
134
|
|
144
|
-
|
145
|
-
|
135
|
+
subject.a.should == 3
|
136
|
+
subject.b.should == 4
|
146
137
|
end
|
147
138
|
|
148
139
|
it "should return a snapshot" do
|
149
|
-
snap =
|
140
|
+
snap = subject.snapshot
|
150
141
|
snap.a.should == 1
|
151
142
|
snap.b.should == 2
|
152
143
|
snap.should == { "a" => 1, "b" => 2 }
|
153
144
|
end
|
154
145
|
|
155
146
|
it "should assign from partial hash" do
|
156
|
-
|
157
|
-
|
158
|
-
|
147
|
+
subject.assign("a" => 3)
|
148
|
+
subject.a.should == 3
|
149
|
+
subject.b.should == 0
|
159
150
|
end
|
160
151
|
|
161
152
|
it "should assign from hash" do
|
162
|
-
|
163
|
-
|
164
|
-
|
153
|
+
subject.assign("a" => 3, "b" => 4)
|
154
|
+
subject.a.should == 3
|
155
|
+
subject.b.should == 4
|
165
156
|
end
|
166
157
|
|
167
158
|
it "should assign from nil" do
|
168
|
-
|
169
|
-
|
159
|
+
subject.assign(nil)
|
160
|
+
subject.should be_clear
|
170
161
|
end
|
171
162
|
|
172
163
|
it "should assign from Struct" do
|
173
|
-
src = BinData::Struct.new(
|
164
|
+
src = BinData::Struct.new(params)
|
174
165
|
src.a = 3
|
175
166
|
src.b = 4
|
176
167
|
|
177
|
-
|
178
|
-
|
179
|
-
|
168
|
+
subject.assign(src)
|
169
|
+
subject.a.should == 3
|
170
|
+
subject.b.should == 4
|
180
171
|
end
|
181
172
|
|
182
173
|
it "should assign from snapshot" do
|
183
|
-
src = BinData::Struct.new(
|
174
|
+
src = BinData::Struct.new(params)
|
184
175
|
src.a = 3
|
185
176
|
src.b = 4
|
186
177
|
|
187
|
-
|
188
|
-
|
189
|
-
|
178
|
+
subject.assign(src.snapshot)
|
179
|
+
subject.a.should == 3
|
180
|
+
subject.b.should == 4
|
190
181
|
end
|
191
182
|
|
192
183
|
it "should fail on unknown method call" do
|
193
|
-
lambda {
|
184
|
+
lambda { subject.does_not_exist }.should raise_error(NoMethodError)
|
194
185
|
end
|
195
186
|
end
|
196
187
|
|
197
188
|
describe BinData::Struct, "with nested structs" do
|
198
|
-
|
189
|
+
subject {
|
199
190
|
inner1 = [ [:int8, :w, {:initial_value => 3}],
|
200
191
|
[:int8, :x, {:value => :the_val}] ]
|
201
192
|
|
202
193
|
inner2 = [ [:int8, :y, {:value => lambda { parent.b.w }}],
|
203
194
|
[:int8, :z] ]
|
204
195
|
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
196
|
+
params = { :fields => [
|
197
|
+
[:int8, :a, {:initial_value => 6}],
|
198
|
+
[:struct, :b, {:fields => inner1, :the_val => :a}],
|
199
|
+
[:struct, :c, {:fields => inner2}]] }
|
200
|
+
BinData::Struct.new(params)
|
201
|
+
}
|
211
202
|
|
212
|
-
|
213
|
-
@obj.field_names.should == ["a", "b", "c"]
|
214
|
-
end
|
203
|
+
its(:field_names) { should == ["a", "b", "c"] }
|
215
204
|
|
216
205
|
it "should return num_bytes" do
|
217
|
-
|
218
|
-
|
219
|
-
|
206
|
+
subject.b.num_bytes.should == 2
|
207
|
+
subject.c.num_bytes.should == 2
|
208
|
+
subject.num_bytes.should == 5
|
220
209
|
end
|
221
210
|
|
222
211
|
it "should access nested fields" do
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
212
|
+
subject.a.should == 6
|
213
|
+
subject.b.w.should == 3
|
214
|
+
subject.b.x.should == 6
|
215
|
+
subject.c.y.should == 3
|
216
|
+
subject.c.z.should == 0
|
228
217
|
end
|
229
218
|
|
230
219
|
it "should return correct offset" do
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
220
|
+
subject.b.offset.should == 1
|
221
|
+
subject.b.w.offset.should == 1
|
222
|
+
subject.c.offset.should == 3
|
223
|
+
subject.c.z.offset.should == 4
|
235
224
|
end
|
236
225
|
end
|
237
226
|
|
238
227
|
describe BinData::Struct, "with an endian defined" do
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
end
|
228
|
+
subject {
|
229
|
+
BinData::Struct.new(:endian => :little,
|
230
|
+
:fields => [
|
231
|
+
[:uint16, :a],
|
232
|
+
[:float, :b],
|
233
|
+
[:array, :c,
|
234
|
+
{:type => :int8, :initial_length => 2}],
|
235
|
+
[:choice, :d,
|
236
|
+
{:choices => [[:uint16], [:uint32]],
|
237
|
+
:selection => 1}],
|
238
|
+
[:struct, :e,
|
239
|
+
{:fields => [[:uint16, :f],
|
240
|
+
[:uint32be, :g]]}],
|
241
|
+
[:struct, :h,
|
242
|
+
{:fields => [
|
243
|
+
[:struct, :i,
|
244
|
+
{:fields => [[:uint16, :j]]}]]}]])
|
245
|
+
}
|
258
246
|
|
259
247
|
it "should use correct endian" do
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
248
|
+
subject.a = 1
|
249
|
+
subject.b = 2.0
|
250
|
+
subject.c[0] = 3
|
251
|
+
subject.c[1] = 4
|
252
|
+
subject.d = 5
|
253
|
+
subject.e.f = 6
|
254
|
+
subject.e.g = 7
|
255
|
+
subject.h.i.j = 8
|
268
256
|
|
269
257
|
expected = [1, 2.0, 3, 4, 5, 6, 7, 8].pack('veCCVvNv')
|
270
258
|
|
271
|
-
|
259
|
+
subject.to_binary_s.should == expected
|
272
260
|
end
|
273
261
|
end
|
274
262
|
|
275
263
|
describe BinData::Struct, "with bit fields" do
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
@obj.b = 2
|
281
|
-
@obj.c = 3
|
282
|
-
@obj.d = 1
|
283
|
-
end
|
264
|
+
subject {
|
265
|
+
params = { :fields => [ [:bit1le, :a], [:bit2le, :b], [:uint8, :c], [:bit1le, :d] ] }
|
266
|
+
BinData::Struct.new({:a => 1, :b => 2, :c => 3, :d => 1}, params)
|
267
|
+
}
|
284
268
|
|
285
|
-
|
286
|
-
|
287
|
-
end
|
288
|
-
|
289
|
-
it "should write" do
|
290
|
-
@obj.to_binary_s.should == [0b0000_0101, 3, 1].pack("C*")
|
291
|
-
end
|
269
|
+
its(:num_bytes) { should == 3 }
|
270
|
+
its(:to_binary_s) { should == [0b0000_0101, 3, 1].pack("C*") }
|
292
271
|
|
293
272
|
it "should read" do
|
294
273
|
str = [0b0000_0110, 5, 0].pack("C*")
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
274
|
+
subject.read(str)
|
275
|
+
subject.a.should == 0
|
276
|
+
subject.b.should == 3
|
277
|
+
subject.c.should == 5
|
278
|
+
subject.d.should == 0
|
300
279
|
end
|
301
280
|
|
302
281
|
it "should have correct offsets" do
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
282
|
+
subject.a.offset.should == 0
|
283
|
+
subject.b.offset.should == 0
|
284
|
+
subject.c.offset.should == 1
|
285
|
+
subject.d.offset.should == 2
|
307
286
|
end
|
308
287
|
end
|
309
288
|
|
@@ -315,12 +294,12 @@ describe BinData::Struct, "with nested endian" do
|
|
315
294
|
:fields => [[:int16, :a],
|
316
295
|
[:struct, :s, nested_params],
|
317
296
|
[:int16, :d]] }
|
318
|
-
|
319
|
-
|
297
|
+
subject = BinData::Struct.new(params)
|
298
|
+
subject.read("\x00\x01\x02\x00\x03\x00\x00\x04")
|
320
299
|
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
300
|
+
subject.a.should == 1
|
301
|
+
subject.s.b.should == 2
|
302
|
+
subject.s.c.should == 3
|
303
|
+
subject.d.should == 4
|
325
304
|
end
|
326
305
|
end
|