bindata 2.4.15 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog.rdoc +11 -0
  3. data/README.md +6 -9
  4. data/bindata.gemspec +3 -3
  5. data/examples/list.rb +1 -1
  6. data/lib/bindata/alignment.rb +15 -7
  7. data/lib/bindata/array.rb +54 -54
  8. data/lib/bindata/base.rb +14 -25
  9. data/lib/bindata/base_primitive.rb +24 -20
  10. data/lib/bindata/bits.rb +5 -5
  11. data/lib/bindata/buffer.rb +89 -11
  12. data/lib/bindata/choice.rb +9 -6
  13. data/lib/bindata/count_bytes_remaining.rb +1 -1
  14. data/lib/bindata/delayed_io.rb +10 -10
  15. data/lib/bindata/dsl.rb +34 -32
  16. data/lib/bindata/float.rb +3 -3
  17. data/lib/bindata/framework.rb +8 -10
  18. data/lib/bindata/int.rb +9 -9
  19. data/lib/bindata/io.rb +276 -253
  20. data/lib/bindata/name.rb +1 -1
  21. data/lib/bindata/params.rb +9 -7
  22. data/lib/bindata/primitive.rb +3 -3
  23. data/lib/bindata/registry.rb +18 -18
  24. data/lib/bindata/rest.rb +1 -1
  25. data/lib/bindata/sanitize.rb +9 -16
  26. data/lib/bindata/section.rb +97 -0
  27. data/lib/bindata/skip.rb +140 -51
  28. data/lib/bindata/string.rb +9 -9
  29. data/lib/bindata/stringz.rb +12 -10
  30. data/lib/bindata/struct.rb +83 -66
  31. data/lib/bindata/trace.rb +35 -42
  32. data/lib/bindata/transform/brotli.rb +35 -0
  33. data/lib/bindata/transform/lz4.rb +35 -0
  34. data/lib/bindata/transform/lzma.rb +35 -0
  35. data/lib/bindata/transform/xor.rb +19 -0
  36. data/lib/bindata/transform/xz.rb +35 -0
  37. data/lib/bindata/transform/zlib.rb +33 -0
  38. data/lib/bindata/transform/zstd.rb +35 -0
  39. data/lib/bindata/uint8_array.rb +2 -2
  40. data/lib/bindata/version.rb +1 -1
  41. data/lib/bindata/virtual.rb +4 -7
  42. data/lib/bindata/warnings.rb +1 -1
  43. data/lib/bindata.rb +1 -0
  44. data/test/array_test.rb +10 -8
  45. data/test/buffer_test.rb +9 -0
  46. data/test/choice_test.rb +1 -1
  47. data/test/delayed_io_test.rb +16 -0
  48. data/test/io_test.rb +54 -246
  49. data/test/registry_test.rb +1 -1
  50. data/test/section_test.rb +111 -0
  51. data/test/skip_test.rb +55 -10
  52. data/test/string_test.rb +4 -4
  53. data/test/stringz_test.rb +8 -0
  54. data/test/struct_test.rb +87 -12
  55. data/test/system_test.rb +119 -1
  56. data/test/test_helper.rb +24 -13
  57. data/test/warnings_test.rb +12 -0
  58. metadata +17 -16
  59. data/lib/bindata/offset.rb +0 -94
  60. data/test/offset_test.rb +0 -100
data/test/array_test.rb CHANGED
@@ -18,17 +18,15 @@ describe BinData::Array, "when instantiating" do
18
18
  end
19
19
 
20
20
  it "warns about :length" do
21
- Kernel.must_warn ":length is not used with BinData::Array. You probably want to change this to :initial_length" do
22
- obj = BinData::Array.new(type: :uint8, length: 3)
23
- obj.read "123"
24
- end
21
+ _ {
22
+ BinData::Array.new(type: :uint8, length: 3)
23
+ }.must_warn ":length is not used with BinData::Array. You probably want to change this to :initial_length"
25
24
  end
26
25
 
27
26
  it "warns about :read_length" do
28
- Kernel.must_warn ":read_length is not used with BinData::Array. You probably want to change this to :initial_length" do
29
- obj = BinData::Array.new(type: :uint8, read_length: 3)
30
- obj.read "123"
31
- end
27
+ _ {
28
+ BinData::Array.new(type: :uint8, read_length: 3)
29
+ }.must_warn ":read_length is not used with BinData::Array. You probably want to change this to :initial_length"
32
30
  end
33
31
 
34
32
  it "fails if a given type is unknown" do
@@ -71,6 +69,10 @@ describe BinData::Array, "with no elements" do
71
69
  it "returns [] for the last n elements" do
72
70
  _(obj.last(3)).must_equal []
73
71
  end
72
+
73
+ it "won't assign nil" do
74
+ _ { obj.assign(nil) }.must_raise ArgumentError
75
+ end
74
76
  end
75
77
 
76
78
  describe BinData::Array, "with several elements" do
data/test/buffer_test.rb CHANGED
@@ -144,6 +144,15 @@ describe BinData::Buffer, "nested buffers" do
144
144
  _(obj.b).must_equal "klmno"
145
145
  end
146
146
 
147
+ it "pads undersize writes" do
148
+ obj = NestedBufferRecord.new
149
+ obj.a.aa = "abc"
150
+ obj.a.bb = "ABC"
151
+ obj.b = "123"
152
+
153
+ _(obj.to_binary_s).must_equal_binary "abc\000\000ABC\000\000123"
154
+ end
155
+
147
156
  it "restricts oversize writes" do
148
157
  obj = NestedBufferRecord.new
149
158
  obj.a.aa = "abcdefghij"
data/test/choice_test.rb CHANGED
@@ -243,7 +243,7 @@ describe BinData::Choice, "subclassed with default parameters" do
243
243
  _(obj.num_bytes).must_equal 2
244
244
  end
245
245
 
246
- it "overides default parameter" do
246
+ it "overrides default parameter" do
247
247
  obj = DerivedChoice.new(selection: 'b')
248
248
  _(obj.num_bytes).must_equal 4
249
249
  end
@@ -266,3 +266,19 @@ describe BinData::DelayedIO, "with auto_call" do
266
266
  _(obj.num_bytes).must_equal 2
267
267
  end
268
268
  end
269
+
270
+ describe BinData::DelayedIO, "with multiple auto_call" do
271
+ class MultipleAutoCallDelayedIORecord < BinData::Record
272
+ auto_call_delayed_io
273
+ auto_call_delayed_io
274
+ uint8 :a
275
+ delayed_io :b, read_abs_offset: 1 do
276
+ uint8
277
+ end
278
+ end
279
+
280
+ it "class reads" do
281
+ obj = MultipleAutoCallDelayedIORecord.read "\x01\x02"
282
+ _(obj.snapshot).must_equal({a: 1, b: 2})
283
+ end
284
+ end
data/test/io_test.rb CHANGED
@@ -15,16 +15,24 @@ describe BinData::IO::Read, "reading from non seekable stream" do
15
15
  @rd.close
16
16
  end
17
17
 
18
- it "has correct offset" do
19
- @io.readbytes(10)
20
- _(@io.offset).must_equal 10
18
+ it "seeks correctly" do
19
+ @io.skipbytes(1999)
20
+ _(@io.readbytes(5)).must_equal "abbbb"
21
21
  end
22
22
 
23
- it "seeks correctly" do
24
- @io.seekbytes(1999)
23
+ it "seeks to abs_offset" do
24
+ @io.skipbytes(1000)
25
+ @io.seek_to_abs_offset(1999)
25
26
  _(@io.readbytes(5)).must_equal "abbbb"
26
27
  end
27
28
 
29
+ it "wont seek backwards" do
30
+ @io.skipbytes(5)
31
+ _ {
32
+ @io.skipbytes(-1)
33
+ }.must_raise IOError
34
+ end
35
+
28
36
  it "#num_bytes_remaining raises IOError" do
29
37
  _ {
30
38
  @io.num_bytes_remaining
@@ -32,6 +40,35 @@ describe BinData::IO::Read, "reading from non seekable stream" do
32
40
  end
33
41
  end
34
42
 
43
+ describe BinData::IO::Write, "writing to non seekable stream" do
44
+ before do
45
+ @rd, @wr = IO::pipe
46
+ @io = BinData::IO::Write.new(@wr)
47
+ end
48
+
49
+ after do
50
+ @rd.close
51
+ @wr.close
52
+ end
53
+
54
+ def written_data
55
+ @io.flush
56
+ @wr.close
57
+ @rd.read
58
+ end
59
+
60
+ it "writes correctly" do
61
+ @io.writebytes("hello")
62
+ _(written_data).must_equal "hello"
63
+ end
64
+
65
+ it "must not attempt to seek" do
66
+ _ {
67
+ @io.seek_to_abs_offset(5)
68
+ }.must_raise IOError
69
+ end
70
+ end
71
+
35
72
  describe BinData::IO::Read, "when reading" do
36
73
  let(:stream) { StringIO.new "abcdefghij" }
37
74
  let(:io) { BinData::IO::Read.new(stream) }
@@ -42,19 +79,19 @@ describe BinData::IO::Read, "when reading" do
42
79
  }.must_raise ArgumentError
43
80
  end
44
81
 
45
- it "returns correct offset" do
46
- stream.seek(3, IO::SEEK_CUR)
47
-
48
- _(io.offset).must_equal 0
49
- _(io.readbytes(4)).must_equal "defg"
50
- _(io.offset).must_equal 4
51
- end
52
-
53
82
  it "seeks correctly" do
54
- io.seekbytes(2)
83
+ io.skipbytes(2)
55
84
  _(io.readbytes(4)).must_equal "cdef"
56
85
  end
57
86
 
87
+ it "wont seek backwards" do
88
+ io.skipbytes(5)
89
+ _ {
90
+ io.skipbytes(-1)
91
+ }.must_raise IOError
92
+ end
93
+
94
+
58
95
  it "reads all bytes" do
59
96
  _(io.read_all_bytes).must_equal "abcdefghij"
60
97
  end
@@ -67,7 +104,7 @@ describe BinData::IO::Read, "when reading" do
67
104
  end
68
105
 
69
106
  it "raises error when reading at eof" do
70
- io.seekbytes(10)
107
+ io.skipbytes(10)
71
108
  _ {
72
109
  io.readbytes(3)
73
110
  }.must_raise EOFError
@@ -80,149 +117,6 @@ describe BinData::IO::Read, "when reading" do
80
117
  end
81
118
  end
82
119
 
83
- describe BinData::IO::Read, "#with_buffer" do
84
- let(:stream) { StringIO.new "abcdefghijklmnopqrst" }
85
- let(:io) { BinData::IO::Read.new(stream) }
86
-
87
- it "consumes entire buffer on short reads" do
88
- io.with_buffer(10) do
89
- _(io.readbytes(4)).must_equal "abcd"
90
- end
91
- _(io.offset).must_equal(10)
92
- end
93
-
94
- it "consumes entire buffer on read_all_bytes" do
95
- io.with_buffer(10) do
96
- _(io.read_all_bytes).must_equal "abcdefghij"
97
- end
98
- _(io.offset).must_equal(10)
99
- end
100
-
101
- it "restricts large reads" do
102
- io.with_buffer(10) do
103
- _ {
104
- io.readbytes(15)
105
- }.must_raise IOError
106
- end
107
- end
108
-
109
- it "is nestable" do
110
- io.with_buffer(10) do
111
- _(io.readbytes(2)).must_equal "ab"
112
- io.with_buffer(5) do
113
- _(io.read_all_bytes).must_equal "cdefg"
114
- end
115
- _(io.offset).must_equal(2 + 5)
116
- end
117
- _(io.offset).must_equal(10)
118
- end
119
-
120
- it "restricts large nested buffers" do
121
- io.with_buffer(10) do
122
- _(io.readbytes(2)).must_equal "ab"
123
- io.with_buffer(20) do
124
- _(io.read_all_bytes).must_equal "cdefghij"
125
- _(io.offset).must_equal(10)
126
- end
127
- end
128
- _(io.offset).must_equal(10)
129
- end
130
-
131
- it "restricts large seeks" do
132
- io.with_buffer(10) do
133
- io.seekbytes(15)
134
- end
135
- _(io.offset).must_equal(10)
136
- end
137
-
138
- it "restricts large -ve seeks" do
139
- io.readbytes(2)
140
- io.with_buffer(10) do
141
- io.seekbytes(-1)
142
- _(io.offset).must_equal(2)
143
- end
144
- end
145
-
146
- it "greater than stream size consumes all bytes" do
147
- io.with_buffer(30) do
148
- _(io.readbytes(4)).must_equal "abcd"
149
- end
150
- _(io.offset).must_equal(20)
151
- end
152
-
153
- it "restricts #num_bytes_remaining" do
154
- io.with_buffer(10) do
155
- io.readbytes(2)
156
- _(io.num_bytes_remaining).must_equal 8
157
- end
158
- end
159
-
160
- it "greater than stream size doesn't restrict #num_bytes_remaining" do
161
- io.with_buffer(30) do
162
- io.readbytes(2)
163
- _(io.num_bytes_remaining).must_equal 18
164
- end
165
- end
166
- end
167
-
168
- module IOReadWithReadahead
169
- def test_rolls_back_short_reads
170
- _(io.readbytes(2)).must_equal "ab"
171
- io.with_readahead do
172
- _(io.readbytes(4)).must_equal "cdef"
173
- end
174
- _(io.offset).must_equal 2
175
- end
176
-
177
- def test_rolls_back_read_all_bytes
178
- _(io.readbytes(3)).must_equal "abc"
179
- io.with_readahead do
180
- _(io.read_all_bytes).must_equal "defghijklmnopqrst"
181
- end
182
- _(io.offset).must_equal 3
183
- end
184
-
185
- def test_inside_buffer_rolls_back_reads
186
- io.with_buffer(10) do
187
- io.with_readahead do
188
- _(io.readbytes(4)).must_equal "abcd"
189
- end
190
- _(io.offset).must_equal 0
191
- end
192
- _(io.offset).must_equal 10
193
- end
194
-
195
- def test_outside_buffer_rolls_back_reads
196
- io.with_readahead do
197
- io.with_buffer(10) do
198
- _(io.readbytes(4)).must_equal "abcd"
199
- end
200
- _(io.offset).must_equal 10
201
- end
202
- _(io.offset).must_equal 0
203
- end
204
- end
205
-
206
- describe BinData::IO::Read, "#with_readahead" do
207
- let(:stream) { StringIO.new "abcdefghijklmnopqrst" }
208
- let(:io) { BinData::IO::Read.new(stream) }
209
-
210
- include IOReadWithReadahead
211
- end
212
-
213
- describe BinData::IO::Read, "unseekable stream #with_readahead" do
214
- let(:stream) {
215
- io = StringIO.new "abcdefghijklmnopqrst"
216
- def io.pos
217
- raise Errno::EPIPE
218
- end
219
- io
220
- }
221
- let(:io) { BinData::IO::Read.new(stream) }
222
-
223
- include IOReadWithReadahead
224
- end
225
-
226
120
  describe BinData::IO::Write, "writing to non seekable stream" do
227
121
  before do
228
122
  @rd, @wr = IO::pipe
@@ -238,30 +132,6 @@ describe BinData::IO::Write, "writing to non seekable stream" do
238
132
  @io.writebytes("1234567890")
239
133
  _(@rd.read(10)).must_equal "1234567890"
240
134
  end
241
-
242
- it "has correct offset" do
243
- @io.writebytes("1234567890")
244
- _(@io.offset).must_equal 10
245
- end
246
-
247
- it "does not seek backwards" do
248
- @io.writebytes("1234567890")
249
- _ {
250
- @io.seekbytes(-5)
251
- }.must_raise IOError
252
- end
253
-
254
- it "does not seek forwards" do
255
- _ {
256
- @io.seekbytes(5)
257
- }.must_raise IOError
258
- end
259
-
260
- it "#num_bytes_remaining raises IOError" do
261
- _ {
262
- @io.num_bytes_remaining
263
- }.must_raise IOError
264
- end
265
135
  end
266
136
 
267
137
  describe BinData::IO::Write, "when writing" do
@@ -280,21 +150,6 @@ describe BinData::IO::Write, "when writing" do
280
150
  _(stream.value).must_equal "abcd"
281
151
  end
282
152
 
283
- it "has #offset" do
284
- _(io.offset).must_equal 0
285
-
286
- io.writebytes("abcd")
287
- _(io.offset).must_equal 4
288
-
289
- io.writebytes("ABCD")
290
- _(io.offset).must_equal 8
291
- end
292
-
293
- it "rounds up #offset when writing bits" do
294
- io.writebits(123, 9, :little)
295
- _(io.offset).must_equal 2
296
- end
297
-
298
153
  it "flushes" do
299
154
  io.writebytes("abcd")
300
155
  io.flush
@@ -303,53 +158,6 @@ describe BinData::IO::Write, "when writing" do
303
158
  end
304
159
  end
305
160
 
306
- describe BinData::IO::Write, "#with_buffer" do
307
- let(:stream) { StringIO.new }
308
- let(:io) { BinData::IO::Write.new(stream) }
309
-
310
- it "pads entire buffer on short reads" do
311
- io.with_buffer(10) do
312
- io.writebytes "abcde"
313
- end
314
-
315
- _(stream.value).must_equal "abcde\0\0\0\0\0"
316
- end
317
-
318
- it "discards excess on large writes" do
319
- io.with_buffer(5) do
320
- io.writebytes "abcdefghij"
321
- end
322
-
323
- _(stream.value).must_equal "abcde"
324
- end
325
-
326
- it "is nestable" do
327
- io.with_buffer(10) do
328
- io.with_buffer(5) do
329
- io.writebytes "abc"
330
- end
331
- io.writebytes "de"
332
- end
333
-
334
- _(stream.value).must_equal "abc\0\0de\0\0\0"
335
- end
336
-
337
- it "restricts large seeks" do
338
- io.with_buffer(10) do
339
- io.seekbytes(15)
340
- end
341
- _(io.offset).must_equal(10)
342
- end
343
-
344
- it "restricts large -ve seeks" do
345
- io.writebytes("12")
346
- io.with_buffer(10) do
347
- io.seekbytes(-1)
348
- _(io.offset).must_equal(2)
349
- end
350
- end
351
- end
352
-
353
161
  describe BinData::IO::Read, "reading bits in big endian" do
354
162
  let(:b1) { 0b1111_1010 }
355
163
  let(:b2) { 0b1100_1110 }
@@ -554,7 +362,7 @@ describe BinData::IO::Write, "writing bits in little endian" do
554
362
  end
555
363
 
556
364
  describe BinData::IO::Read, "with changing endian" do
557
- it "does not mix different endianess when reading" do
365
+ it "does not mix different endianness when reading" do
558
366
  b1 = 0b0110_1010
559
367
  b2 = 0b1110_0010
560
368
  str = [b1, b2].pack("CC")
@@ -566,7 +374,7 @@ describe BinData::IO::Read, "with changing endian" do
566
374
  end
567
375
 
568
376
  describe BinData::IO::Write, "with changing endian" do
569
- it "does not mix different endianess when writing" do
377
+ it "does not mix different endianness when writing" do
570
378
  io = BitWriterHelper.new
571
379
  io.writebits(0b110, 3, :big)
572
380
  io.writebits(0b010, 3, :little)
@@ -36,7 +36,7 @@ describe BinData::Registry do
36
36
  end
37
37
 
38
38
  it "allows overriding of registered classes" do
39
- w, $-w = $-w, false
39
+ w, $-w = $-w, nil # disable warning
40
40
 
41
41
  begin
42
42
  r.register('A', A)
@@ -0,0 +1,111 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
4
+
5
+ describe BinData::Section do
6
+ it "transforms data byte at a time" do
7
+ require 'bindata/transform/xor'
8
+
9
+ obj = BinData::Section.new(transform: -> { BinData::Transform::Xor.new(0xff) },
10
+ type: [:string, read_length: 5])
11
+
12
+ _(obj.read("\x97\x9A\x93\x93\x90")).must_equal "hello"
13
+ end
14
+
15
+ begin
16
+ require 'brotli'
17
+ it "transform brotli" do
18
+ require 'bindata/transform/brotli'
19
+
20
+ class BrotliRecord < BinData::Record
21
+ int32le :len, value: -> { s.num_bytes }
22
+ section :s, transform: -> { BinData::Transform::Brotli.new(len) } do
23
+ int32le :str_len, value: -> { str.length }
24
+ string :str, read_length: :str_len
25
+
26
+ end
27
+ end
28
+
29
+ obj = BrotliRecord.new
30
+ data = "highly compressible" * 100
31
+ obj.s.str = data
32
+ _(obj.len).must_be :<, (data.length / 10)
33
+
34
+ str = obj.to_binary_s
35
+ obj = BrotliRecord.read(str)
36
+ _(obj.s.str).must_equal data
37
+ end
38
+ rescue LoadError; end
39
+
40
+ begin
41
+ require 'extlz4'
42
+ it "transform lz4" do
43
+ require 'bindata/transform/lz4'
44
+
45
+ class LZ4Record < BinData::Record
46
+ int32le :len, value: -> { s.num_bytes }
47
+ section :s, transform: -> { BinData::Transform::LZ4.new(len) } do
48
+ int32le :str_len, value: -> { str.length }
49
+ string :str, read_length: :str_len
50
+
51
+ end
52
+ end
53
+
54
+ obj = LZ4Record.new
55
+ data = "highly compressible" * 100
56
+ obj.s.str = data
57
+ _(obj.len).must_be :<, (data.length / 10)
58
+
59
+ str = obj.to_binary_s
60
+ obj = LZ4Record.read(str)
61
+ _(obj.s.str).must_equal data
62
+ end
63
+ rescue LoadError; end
64
+
65
+ it "transform zlib" do
66
+ require 'bindata/transform/zlib'
67
+
68
+ class ZlibRecord < BinData::Record
69
+ int32le :len, value: -> { s.num_bytes }
70
+ section :s, transform: -> { BinData::Transform::Zlib.new(len) } do
71
+ int32le :str_len, value: -> { str.length }
72
+ string :str, read_length: :str_len
73
+
74
+ end
75
+ end
76
+
77
+ obj = ZlibRecord.new
78
+ data = "highly compressible" * 100
79
+ obj.s.str = data
80
+ _(obj.len).must_be :<, (data.length / 10)
81
+
82
+ str = obj.to_binary_s
83
+ obj = ZlibRecord.read(str)
84
+ _(obj.s.str).must_equal data
85
+ end
86
+
87
+ begin
88
+ require 'zstd-ruby'
89
+ it "transform zstd" do
90
+ require 'bindata/transform/zstd'
91
+
92
+ class ZstdRecord < BinData::Record
93
+ int32le :len, value: -> { s.num_bytes }
94
+ section :s, transform: -> { BinData::Transform::Zstd.new(len) } do
95
+ int32le :str_len, value: -> { str.length }
96
+ string :str, read_length: :str_len
97
+
98
+ end
99
+ end
100
+
101
+ obj = ZstdRecord.new
102
+ data = "highly compressible" * 100
103
+ obj.s.str = data
104
+ _(obj.len).must_be :<, (data.length / 10)
105
+
106
+ str = obj.to_binary_s
107
+ obj = ZstdRecord.read(str)
108
+ _(obj.s.str).must_equal data
109
+ end
110
+ rescue LoadError; end
111
+ end
data/test/skip_test.rb CHANGED
@@ -62,7 +62,7 @@ describe BinData::Skip, "with :to_abs_offset" do
62
62
 
63
63
  _ {
64
64
  obj.read(io)
65
- }.must_raise BinData::ValidityError
65
+ }.must_raise ArgumentError
66
66
  end
67
67
 
68
68
  it "writes skipping forward" do
@@ -82,13 +82,20 @@ describe BinData::Skip, "with :to_abs_offset" do
82
82
  obj = BinData::Struct.new(fields: fields)
83
83
  _ {
84
84
  obj.to_binary_s
85
- }.must_raise BinData::ValidityError
85
+ }.must_raise ArgumentError
86
86
  end
87
87
  end
88
88
 
89
89
  describe BinData::Skip, "with :until_valid" do
90
90
  let(:io) { StringIO.new("abcdefghij") }
91
91
 
92
+ it "doesn't skip when writing" do
93
+ skip_obj = [:string, { read_length: 1, assert: "f" }]
94
+ args = { until_valid: skip_obj }
95
+ obj = BinData::Skip.new(args)
96
+ _(obj.to_binary_s).must_equal ""
97
+ end
98
+
92
99
  it "skips to valid match" do
93
100
  skip_obj = [:string, { read_length: 1, assert: "f" }]
94
101
  fields = [ [:skip, :s, { until_valid: skip_obj }] ]
@@ -97,6 +104,19 @@ describe BinData::Skip, "with :until_valid" do
97
104
  _(io.pos).must_equal 5
98
105
  end
99
106
 
107
+ it "won't skip on unseekable stream" do
108
+ rd, wr = IO::pipe
109
+ unseekable_io = BinData::IO::Read.new(rd)
110
+ wr.write io
111
+ wr.close
112
+
113
+ skip_obj = [:string, { read_length: 1, assert: "f" }]
114
+ fields = [ [:skip, :s, { until_valid: skip_obj }] ]
115
+ obj = BinData::Struct.new(fields: fields)
116
+ _ {obj.read(unseekable_io)}.must_raise IOError
117
+ rd.close
118
+ end
119
+
100
120
  it "doesn't skip when validator doesn't assert" do
101
121
  skip_obj = [:string, { read_length: 1 }]
102
122
  fields = [ [:skip, :s, { until_valid: skip_obj }] ]
@@ -105,13 +125,13 @@ describe BinData::Skip, "with :until_valid" do
105
125
  _(io.pos).must_equal 0
106
126
  end
107
127
 
108
- it "raises EOFError when no match" do
128
+ it "raises IOError when no match" do
109
129
  skip_obj = [:string, { read_length: 1, assert: "X" }]
110
130
  fields = [ [:skip, :s, { until_valid: skip_obj }] ]
111
131
  obj = BinData::Struct.new(fields: fields)
112
132
  _ {
113
133
  obj.read(io)
114
- }.must_raise EOFError
134
+ }.must_raise IOError
115
135
  end
116
136
 
117
137
  it "raises IOError when validator reads beyond stream" do
@@ -123,15 +143,40 @@ describe BinData::Skip, "with :until_valid" do
123
143
  }.must_raise IOError
124
144
  end
125
145
 
126
- class DSLSkip < BinData::Record
127
- skip :s do
128
- string read_length: 1, assert: "f"
146
+ it "uses block form" do
147
+ class DSLSkip < BinData::Record
148
+ skip :s do
149
+ string read_length: 1, assert: "f"
150
+ end
151
+ string :a, read_length: 1
129
152
  end
130
- string :a, read_length: 1
131
- end
132
153
 
133
- it "uses block form" do
134
154
  obj = DSLSkip.read(io)
135
155
  _(obj.a).must_equal "f"
136
156
  end
137
157
  end
158
+
159
+ describe BinData::Skip, "with :until_valid" do
160
+ class SkipSearch < BinData::Record
161
+ skip :s do
162
+ uint8
163
+ uint8 asserted_value: 1
164
+ uint8 :a
165
+ uint8 :b
166
+ virtual assert: -> { a == b }
167
+ end
168
+ array :data, type: :uint8, initial_length: 4
169
+ end
170
+
171
+ let(:io) { BinData::IO.create_string_io("\x0f" * 10 + "\x00\x01\x02\x03\x00" + "\x02\x01\x03\x03" + "\x06") }
172
+
173
+ it "finds valid match" do
174
+ obj = SkipSearch.read(io)
175
+ _(obj.data).must_equal [2, 1, 3, 3]
176
+ end
177
+
178
+ it "match is at expected offset" do
179
+ obj = SkipSearch.read(io)
180
+ _(obj.data.rel_offset).must_equal 15
181
+ end
182
+ end