bzip2-ffi 1.0.0
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.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +2 -0
- data.tar.gz.sig +1 -0
- data/.yardopts +7 -0
- data/CHANGES.md +4 -0
- data/Gemfile +14 -0
- data/LICENSE +19 -0
- data/README.md +144 -0
- data/Rakefile +62 -0
- data/bzip2-ffi.gemspec +30 -0
- data/lib/bzip2/ffi.rb +14 -0
- data/lib/bzip2/ffi/error.rb +100 -0
- data/lib/bzip2/ffi/io.rb +250 -0
- data/lib/bzip2/ffi/libbz2.rb +75 -0
- data/lib/bzip2/ffi/reader.rb +422 -0
- data/lib/bzip2/ffi/version.rb +6 -0
- data/lib/bzip2/ffi/writer.rb +373 -0
- data/test/error_test.rb +38 -0
- data/test/fixtures/bzipped +0 -0
- data/test/fixtures/lorem.txt +2440 -0
- data/test/fixtures/moon.tiff +0 -0
- data/test/fixtures/zero.txt +512 -0
- data/test/io_test.rb +382 -0
- data/test/reader_test.rb +498 -0
- data/test/test_helper.rb +98 -0
- data/test/version_test.rb +7 -0
- data/test/writer_test.rb +439 -0
- metadata +117 -0
- metadata.gz.sig +1 -0
data/test/io_test.rb
ADDED
@@ -0,0 +1,382 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class IOTest < Minitest::Test
|
4
|
+
class DummyIO
|
5
|
+
def initialize
|
6
|
+
@closed = false
|
7
|
+
end
|
8
|
+
|
9
|
+
def close
|
10
|
+
@closed = true
|
11
|
+
end
|
12
|
+
|
13
|
+
def closed?
|
14
|
+
@closed
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class NoCloseIO
|
19
|
+
end
|
20
|
+
|
21
|
+
class TestIO < Bzip2::FFI::IO
|
22
|
+
class << self
|
23
|
+
public :new
|
24
|
+
public :open
|
25
|
+
end
|
26
|
+
|
27
|
+
public :io
|
28
|
+
public :stream
|
29
|
+
public :check_closed
|
30
|
+
public :check_error
|
31
|
+
|
32
|
+
def initialize(io, options = {})
|
33
|
+
super
|
34
|
+
|
35
|
+
raise 'test' if options[:test_initialize_raise_exception]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_autoclose_set_true
|
40
|
+
io = TestIO.new(DummyIO.new, autoclose: false)
|
41
|
+
assert_equal(false, io.autoclose?)
|
42
|
+
io.autoclose = true
|
43
|
+
assert_equal(true, io.autoclose?)
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_autoclose_set_truthy
|
47
|
+
io = TestIO.new(DummyIO.new, autoclose: false)
|
48
|
+
assert_equal(false, io.autoclose?)
|
49
|
+
io.autoclose = 'false'
|
50
|
+
assert_equal(true, io.autoclose?)
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_autoclose_set_false
|
54
|
+
io = TestIO.new(DummyIO.new, autoclose: true)
|
55
|
+
assert_equal(true, io.autoclose?)
|
56
|
+
io.autoclose = false
|
57
|
+
assert_equal(false, io.autoclose?)
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_autoclose_set_not_truthy
|
61
|
+
io = TestIO.new(DummyIO.new, autoclose: true)
|
62
|
+
assert_equal(true, io.autoclose?)
|
63
|
+
io.autoclose = nil
|
64
|
+
assert_equal(false, io.autoclose?)
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_autoclose_get_when_closed
|
68
|
+
io = TestIO.new(DummyIO.new)
|
69
|
+
io.close
|
70
|
+
assert_raises(IOError) { io.autoclose? }
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_autoclose_set_when_closed
|
74
|
+
io = TestIO.new(DummyIO.new)
|
75
|
+
io.close
|
76
|
+
assert_raises(IOError) { io.autoclose = true }
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_binmode?
|
80
|
+
io = TestIO.new(DummyIO.new)
|
81
|
+
assert_equal(true, io.binmode?)
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_binmode_get_when_closed
|
85
|
+
io = TestIO.new(DummyIO.new)
|
86
|
+
io.close
|
87
|
+
assert_raises(IOError) { io.binmode? }
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_binmode
|
91
|
+
io = TestIO.new(DummyIO.new)
|
92
|
+
assert_same(io, io.binmode)
|
93
|
+
assert_equal(true, io.binmode?)
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_binmode_set_when_closed
|
97
|
+
io = TestIO.new(DummyIO.new)
|
98
|
+
io.close
|
99
|
+
assert_raises(IOError) { io.binmode }
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_close_without_autoclose
|
103
|
+
dummy_io = DummyIO.new
|
104
|
+
io = TestIO.new(dummy_io)
|
105
|
+
refute(dummy_io.closed?)
|
106
|
+
io.close
|
107
|
+
refute(dummy_io.closed?)
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_close_with_autoclose
|
111
|
+
dummy_io = DummyIO.new
|
112
|
+
io = TestIO.new(dummy_io, autoclose: true)
|
113
|
+
refute(dummy_io.closed?)
|
114
|
+
io.close
|
115
|
+
assert(dummy_io.closed?)
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_close_with_unclosable_and_autoclose
|
119
|
+
no_close_io = NoCloseIO.new
|
120
|
+
io = TestIO.new(no_close_io, autoclose: true)
|
121
|
+
assert_nothing_raised { io.close }
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_close_returns_nil
|
125
|
+
io = TestIO.new(DummyIO.new)
|
126
|
+
assert_nil(io.close)
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_close_when_closed
|
130
|
+
io = TestIO.new(DummyIO.new)
|
131
|
+
io.close
|
132
|
+
assert_raises(IOError) { io.close }
|
133
|
+
end
|
134
|
+
|
135
|
+
def test_closed
|
136
|
+
io = TestIO.new(DummyIO.new)
|
137
|
+
assert_equal(false, io.closed?)
|
138
|
+
io.close
|
139
|
+
assert_equal(true, io.closed?)
|
140
|
+
end
|
141
|
+
|
142
|
+
def test_external_encoding
|
143
|
+
io = TestIO.new(DummyIO.new)
|
144
|
+
assert_equal(Encoding::ASCII_8BIT, io.external_encoding)
|
145
|
+
end
|
146
|
+
|
147
|
+
def test_external_encoding_when_closed
|
148
|
+
io = TestIO.new(DummyIO.new)
|
149
|
+
io.close
|
150
|
+
assert_raises(IOError) { io.external_encoding }
|
151
|
+
end
|
152
|
+
|
153
|
+
def test_internal_encoding
|
154
|
+
io = TestIO.new(DummyIO.new)
|
155
|
+
assert_equal(Encoding::ASCII_8BIT, io.internal_encoding)
|
156
|
+
end
|
157
|
+
|
158
|
+
def test_internal_encoding_when_closed
|
159
|
+
io = TestIO.new(DummyIO.new)
|
160
|
+
io.close
|
161
|
+
assert_raises(IOError) { io.internal_encoding }
|
162
|
+
end
|
163
|
+
|
164
|
+
def test_io
|
165
|
+
dummy_io = DummyIO.new
|
166
|
+
io = TestIO.new(dummy_io)
|
167
|
+
assert_same(dummy_io, io.io)
|
168
|
+
end
|
169
|
+
|
170
|
+
def test_initialize_nil_io
|
171
|
+
assert_raises(ArgumentError) { TestIO.new }
|
172
|
+
end
|
173
|
+
|
174
|
+
def test_initialize_calls_binmode_on_io
|
175
|
+
dummy_io = Minitest::Mock.new
|
176
|
+
dummy_io.expect(:binmode, dummy_io)
|
177
|
+
TestIO.new(dummy_io)
|
178
|
+
assert(dummy_io.verify)
|
179
|
+
end
|
180
|
+
|
181
|
+
def test_initialize_autoclose_default
|
182
|
+
io = TestIO.new(DummyIO.new)
|
183
|
+
assert_equal(false, io.autoclose?)
|
184
|
+
end
|
185
|
+
|
186
|
+
def test_initialize_autoclose_option
|
187
|
+
io = TestIO.new(DummyIO.new, autoclose: true)
|
188
|
+
assert_equal(true, io.autoclose?)
|
189
|
+
end
|
190
|
+
|
191
|
+
def test_stream
|
192
|
+
io = TestIO.new(DummyIO.new)
|
193
|
+
s = io.stream
|
194
|
+
refute_nil(s)
|
195
|
+
assert_kind_of(Bzip2::FFI::Libbz2::BzStream, s)
|
196
|
+
end
|
197
|
+
|
198
|
+
def test_stream_when_closed
|
199
|
+
io = TestIO.new(DummyIO.new)
|
200
|
+
io.close
|
201
|
+
assert_raises(IOError) { io.stream }
|
202
|
+
end
|
203
|
+
|
204
|
+
def test_check_closed_when_open
|
205
|
+
io = TestIO.new(DummyIO.new)
|
206
|
+
assert_nothing_raised { io.check_closed }
|
207
|
+
end
|
208
|
+
|
209
|
+
def test_check_closed_when_closed
|
210
|
+
io = TestIO.new(DummyIO.new)
|
211
|
+
io.close
|
212
|
+
e = assert_raises(IOError) { io.check_closed }
|
213
|
+
assert_equal('closed stream', e.message)
|
214
|
+
end
|
215
|
+
|
216
|
+
def test_check_error_not_error
|
217
|
+
io = TestIO.new(DummyIO.new)
|
218
|
+
|
219
|
+
(0..4).each do |i|
|
220
|
+
assert_equal(i, io.check_error(i))
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def test_check_error_error
|
225
|
+
codes = {
|
226
|
+
Bzip2::FFI::Libbz2::BZ_SEQUENCE_ERROR => Bzip2::FFI::Error::SequenceError,
|
227
|
+
Bzip2::FFI::Libbz2::BZ_PARAM_ERROR => Bzip2::FFI::Error::ParamError,
|
228
|
+
Bzip2::FFI::Libbz2::BZ_MEM_ERROR => Bzip2::FFI::Error::MemoryError,
|
229
|
+
Bzip2::FFI::Libbz2::BZ_DATA_ERROR => Bzip2::FFI::Error::DataError,
|
230
|
+
Bzip2::FFI::Libbz2::BZ_DATA_ERROR_MAGIC => Bzip2::FFI::Error::MagicDataError,
|
231
|
+
Bzip2::FFI::Libbz2::BZ_CONFIG_ERROR => Bzip2::FFI::Error::ConfigError
|
232
|
+
}
|
233
|
+
|
234
|
+
io = TestIO.new(DummyIO.new)
|
235
|
+
|
236
|
+
codes.each do |code, error_class|
|
237
|
+
assert_raises(error_class) { io.check_error(code) }
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
def test_check_error_unexpected
|
242
|
+
io = TestIO.new(DummyIO.new)
|
243
|
+
|
244
|
+
# -6, -7 and -8 are codes that are only raised by the libbz2 high-level
|
245
|
+
# interface. Only the low-level interface is used by Bzip2::FFI.
|
246
|
+
# -10 is not defined by libbz2.
|
247
|
+
[-6, -7, -8, -10].each do |code|
|
248
|
+
error = assert_raises(Bzip2::FFI::Error::UnexpectedError) { io.check_error(code) }
|
249
|
+
assert_includes(error.message, code.to_s)
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
def test_open_no_block
|
254
|
+
dummy_io = DummyIO.new
|
255
|
+
io = TestIO.open(dummy_io)
|
256
|
+
assert_kind_of(TestIO, io)
|
257
|
+
refute(io.closed?)
|
258
|
+
assert_equal(false, io.autoclose?)
|
259
|
+
assert_same(dummy_io, io.io)
|
260
|
+
end
|
261
|
+
|
262
|
+
def test_open_no_block_options
|
263
|
+
dummy_io = DummyIO.new
|
264
|
+
io = TestIO.open(dummy_io, autoclose: true)
|
265
|
+
assert_kind_of(TestIO, io)
|
266
|
+
refute(io.closed?)
|
267
|
+
assert_equal(true, io.autoclose?)
|
268
|
+
assert_same(dummy_io, io.io)
|
269
|
+
end
|
270
|
+
|
271
|
+
def test_open_no_block_proc
|
272
|
+
dummy_io = nil
|
273
|
+
io = TestIO.open(-> { dummy_io = DummyIO.new })
|
274
|
+
refute_nil(dummy_io)
|
275
|
+
assert_same(dummy_io, io.io)
|
276
|
+
refute(dummy_io.closed?)
|
277
|
+
end
|
278
|
+
|
279
|
+
def test_open_no_block_proc_closed_on_exception
|
280
|
+
dummy_io = nil
|
281
|
+
|
282
|
+
assert_raises(RuntimeError) do
|
283
|
+
TestIO.open(-> { dummy_io = DummyIO.new }, test_initialize_raise_exception: true)
|
284
|
+
end
|
285
|
+
|
286
|
+
refute_nil(dummy_io)
|
287
|
+
assert(dummy_io.closed?)
|
288
|
+
end
|
289
|
+
|
290
|
+
def test_open_no_block_proc_closed_on_exception_unless_no_close
|
291
|
+
no_close_io = nil
|
292
|
+
|
293
|
+
assert_raises(RuntimeError) do
|
294
|
+
TestIO.open(-> { no_close_io = NoCloseIO.new }, test_initialize_raise_exception: true)
|
295
|
+
end
|
296
|
+
|
297
|
+
refute_nil(no_close_io)
|
298
|
+
end
|
299
|
+
|
300
|
+
def test_open_block
|
301
|
+
dummy_io = DummyIO.new
|
302
|
+
copy_io = nil
|
303
|
+
|
304
|
+
res = TestIO.open(dummy_io) do |io|
|
305
|
+
assert_kind_of(TestIO, io)
|
306
|
+
refute(io.closed?)
|
307
|
+
assert_equal(false, io.autoclose?)
|
308
|
+
assert_same(dummy_io, io.io)
|
309
|
+
copy_io = io
|
310
|
+
42
|
311
|
+
end
|
312
|
+
|
313
|
+
assert(copy_io.closed?)
|
314
|
+
assert_equal(42, res)
|
315
|
+
end
|
316
|
+
|
317
|
+
def test_open_block_options
|
318
|
+
dummy_io = DummyIO.new
|
319
|
+
copy_io = nil
|
320
|
+
|
321
|
+
res = TestIO.open(dummy_io, autoclose: true) do |io|
|
322
|
+
assert_kind_of(TestIO, io)
|
323
|
+
refute(io.closed?)
|
324
|
+
assert_equal(true, io.autoclose?)
|
325
|
+
assert_same(dummy_io, io.io)
|
326
|
+
copy_io = io
|
327
|
+
42
|
328
|
+
end
|
329
|
+
|
330
|
+
assert(copy_io.closed?)
|
331
|
+
assert_equal(42, res)
|
332
|
+
end
|
333
|
+
|
334
|
+
def test_open_block_closes
|
335
|
+
# Shouldn't raise an exception if the block closes the io.
|
336
|
+
res = TestIO.open(DummyIO.new) do |io|
|
337
|
+
io.close
|
338
|
+
:block_closed
|
339
|
+
end
|
340
|
+
|
341
|
+
assert_equal(:block_closed, res)
|
342
|
+
end
|
343
|
+
|
344
|
+
def test_open_block_proc
|
345
|
+
dummy_io = nil
|
346
|
+
|
347
|
+
TestIO.open(-> { dummy_io = DummyIO.new }) do |io|
|
348
|
+
refute_nil(dummy_io)
|
349
|
+
assert_same(dummy_io, io.io)
|
350
|
+
refute(dummy_io.closed?)
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
354
|
+
def test_open_block_proc_closed_on_exception
|
355
|
+
dummy_io = nil
|
356
|
+
|
357
|
+
assert_raises(RuntimeError) do
|
358
|
+
TestIO.open(-> { dummy_io = DummyIO.new }, test_initialize_raise_exception: true) do |io|
|
359
|
+
flunk('block should not be called')
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
refute_nil(dummy_io)
|
364
|
+
assert(dummy_io.closed?)
|
365
|
+
end
|
366
|
+
|
367
|
+
def test_open_block_proc_closed_on_exception_unless_no_close
|
368
|
+
no_close_io = nil
|
369
|
+
|
370
|
+
assert_raises(RuntimeError) do
|
371
|
+
TestIO.open(-> { no_close_io = NoCloseIO.new }, test_initialize_raise_exception: true) do |io|
|
372
|
+
flunk('block should not be called')
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
refute_nil(no_close_io)
|
377
|
+
end
|
378
|
+
|
379
|
+
def test_open_io_nil
|
380
|
+
assert_raises(ArgumentError) { TestIO.open(nil) }
|
381
|
+
end
|
382
|
+
end
|
data/test/reader_test.rb
ADDED
@@ -0,0 +1,498 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'pathname'
|
3
|
+
require 'stringio'
|
4
|
+
require 'test_helper'
|
5
|
+
require 'tmpdir'
|
6
|
+
|
7
|
+
class ReaderTest < Minitest::Test
|
8
|
+
class StringIOWithoutSeek < StringIO
|
9
|
+
undef_method :seek
|
10
|
+
end
|
11
|
+
|
12
|
+
def setup
|
13
|
+
Bzip2::FFI::Reader.test_after_open_file_raise_exception = false
|
14
|
+
end
|
15
|
+
|
16
|
+
def teardown
|
17
|
+
Bzip2::FFI::Reader.test_after_open_file_raise_exception = false
|
18
|
+
Bzip2::FFI::Reader.test_after_open_file_last_io = nil
|
19
|
+
end
|
20
|
+
|
21
|
+
def compare_fixture(reader, fixture, read_size = nil, use_outbuf = nil)
|
22
|
+
File.open(fixture_path(fixture), 'rb') do |input|
|
23
|
+
if read_size
|
24
|
+
loop do
|
25
|
+
buffer = input.read(read_size)
|
26
|
+
|
27
|
+
if use_outbuf
|
28
|
+
outbuf = 'outbuf'
|
29
|
+
decompressed = reader.read(read_size, outbuf)
|
30
|
+
|
31
|
+
if decompressed
|
32
|
+
assert_same(outbuf, decompressed)
|
33
|
+
else
|
34
|
+
assert_equal('', outbuf)
|
35
|
+
end
|
36
|
+
else
|
37
|
+
decompressed = reader.read(read_size)
|
38
|
+
end
|
39
|
+
|
40
|
+
if buffer
|
41
|
+
assert_same(Encoding::ASCII_8BIT, decompressed.encoding)
|
42
|
+
assert_equal(buffer, decompressed)
|
43
|
+
else
|
44
|
+
assert_nil(decompressed)
|
45
|
+
break
|
46
|
+
end
|
47
|
+
end
|
48
|
+
else
|
49
|
+
buffer = input.read
|
50
|
+
|
51
|
+
if use_outbuf
|
52
|
+
outbuf = 'outbuf'
|
53
|
+
decompressed = reader.read(nil, outbuf)
|
54
|
+
assert_same(outbuf, decompressed)
|
55
|
+
else
|
56
|
+
decompressed = reader.read
|
57
|
+
end
|
58
|
+
|
59
|
+
refute_nil(decompressed)
|
60
|
+
assert_same(Encoding::ASCII_8BIT, decompressed.encoding)
|
61
|
+
assert_equal(buffer, decompressed)
|
62
|
+
end
|
63
|
+
|
64
|
+
assert_nil(reader.read(1))
|
65
|
+
assert_equal(0, reader.read.bytesize)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def bzip_test(fixture, options = {})
|
70
|
+
Dir.mktmpdir('bzip2-ffi-test') do |dir|
|
71
|
+
uncompressed = File.join(dir, 'test')
|
72
|
+
if fixture
|
73
|
+
FileUtils.cp(fixture_path(fixture), uncompressed)
|
74
|
+
else
|
75
|
+
FileUtils.touch(uncompressed)
|
76
|
+
end
|
77
|
+
|
78
|
+
assert_bzip2_successful(uncompressed)
|
79
|
+
|
80
|
+
compressed = File.join(dir, "test.bz2")
|
81
|
+
assert(File.exist?(compressed))
|
82
|
+
|
83
|
+
Bzip2::FFI::Reader.open(compressed, options[:reader_options] || {}) do |reader|
|
84
|
+
if fixture
|
85
|
+
compare_fixture(reader, fixture, options[:read_size], options[:use_outbuf])
|
86
|
+
else
|
87
|
+
assert_equal(0, reader.read.bytesize)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_initialize_nil_io
|
94
|
+
assert_raises(ArgumentError) { Bzip2::FFI::Reader.new(nil) }
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_initialize_io_with_no_read_method
|
98
|
+
assert_raises(ArgumentError) { Bzip2::FFI::Reader.new(Object.new) }
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_empty
|
102
|
+
bzip_test(nil)
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_fixture_text
|
106
|
+
[16, 1024, 16384, File.size(fixture_path('lorem.txt')), nil].each do |read_size|
|
107
|
+
[false, true].each do |use_outbuf|
|
108
|
+
bzip_test('lorem.txt', read_size: read_size, use_outbuf: use_outbuf)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_fixture_very_compressible
|
114
|
+
[16, 1024, 16384, File.size(fixture_path('zero.txt')), nil].each do |read_size|
|
115
|
+
[false, true].each do |use_outbuf|
|
116
|
+
bzip_test('zero.txt', read_size: read_size, use_outbuf: use_outbuf)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def test_fixture_uncompressible
|
122
|
+
[16, 1024, 16384, File.size(fixture_path('bzipped')), nil].each do |read_size|
|
123
|
+
[false, true].each do |use_outbuf|
|
124
|
+
bzip_test('bzipped', read_size: read_size, use_outbuf: use_outbuf)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_fixture_image
|
130
|
+
[16, 1024, 16384, File.size(fixture_path('moon.tiff')), nil].each do |read_size|
|
131
|
+
[false, true].each do |use_outbuf|
|
132
|
+
bzip_test('moon.tiff', read_size: read_size, use_outbuf: use_outbuf)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def test_small
|
138
|
+
# Not trivial to check if the value passed has any effect. Just check that
|
139
|
+
# there are no failures.
|
140
|
+
[false, true].each do |small|
|
141
|
+
bzip_test('lorem.txt', reader_options: {small: small})
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def test_close_mid_read
|
146
|
+
Bzip2::FFI::Reader.open(fixture_path('bzipped')) do |reader|
|
147
|
+
decompressed = reader.read(1)
|
148
|
+
refute_nil(decompressed)
|
149
|
+
assert_equal(1, decompressed.bytesize)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def test_read_zero_before_eof
|
154
|
+
Bzip2::FFI::Reader.open(fixture_path('bzipped')) do |reader|
|
155
|
+
decompressed = reader.read(0)
|
156
|
+
refute_nil(decompressed)
|
157
|
+
assert_equal(0, decompressed.bytesize)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def test_read_zero_before_eof_buffer
|
162
|
+
Bzip2::FFI::Reader.open(fixture_path('bzipped')) do |reader|
|
163
|
+
buffer = 'outbuf'
|
164
|
+
decompressed = reader.read(0, buffer)
|
165
|
+
assert_same(buffer, decompressed)
|
166
|
+
assert_equal(0, decompressed.bytesize)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def test_read_zero_after_eof
|
171
|
+
Bzip2::FFI::Reader.open(fixture_path('bzipped')) do |reader|
|
172
|
+
reader.read
|
173
|
+
decompressed = reader.read(0) # would return nil if greater than 0
|
174
|
+
refute_nil(decompressed)
|
175
|
+
assert_equal(0, decompressed.bytesize)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def test_read_zero_after_eof_buffer
|
180
|
+
Bzip2::FFI::Reader.open(fixture_path('bzipped')) do |reader|
|
181
|
+
reader.read
|
182
|
+
buffer = 'outbuf'
|
183
|
+
decompressed = reader.read(0, buffer) # would return nil if greater than 0
|
184
|
+
assert_same(buffer, decompressed)
|
185
|
+
assert_equal(0, decompressed.bytesize)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def test_read_after_close_read_all
|
190
|
+
File.open(fixture_path('bzipped'), 'rb') do |file|
|
191
|
+
reader = Bzip2::FFI::Reader.new(file)
|
192
|
+
reader.close
|
193
|
+
assert_raises(IOError) { reader.read }
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def test_read_after_close_read_all_buffer
|
198
|
+
File.open(fixture_path('bzipped'), 'rb') do |file|
|
199
|
+
reader = Bzip2::FFI::Reader.new(file)
|
200
|
+
reader.close
|
201
|
+
assert_raises(IOError) { reader.read(nil, '') }
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def test_read_after_close_read_n
|
206
|
+
File.open(fixture_path('bzipped'), 'rb') do |file|
|
207
|
+
reader = Bzip2::FFI::Reader.new(file)
|
208
|
+
reader.close
|
209
|
+
assert_raises(IOError) { reader.read(1) }
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def test_read_after_close_read_n_buffer
|
214
|
+
File.open(fixture_path('bzipped'), 'rb') do |file|
|
215
|
+
reader = Bzip2::FFI::Reader.new(file)
|
216
|
+
reader.close
|
217
|
+
assert_raises(IOError) { reader.read(1, '') }
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
def test_read_after_close_read_zero
|
222
|
+
File.open(fixture_path('bzipped'), 'rb') do |file|
|
223
|
+
reader = Bzip2::FFI::Reader.new(file)
|
224
|
+
reader.close
|
225
|
+
assert_raises(IOError) { reader.read(0) }
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
def test_read_after_close_read_zero_buffer
|
230
|
+
File.open(fixture_path('bzipped'), 'rb') do |file|
|
231
|
+
reader = Bzip2::FFI::Reader.new(file)
|
232
|
+
reader.close
|
233
|
+
assert_raises(IOError) { reader.read(0, '') }
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
def test_close_returns_nil
|
238
|
+
reader = Bzip2::FFI::Reader.new(StringIO.new)
|
239
|
+
assert_nil(reader.close)
|
240
|
+
end
|
241
|
+
|
242
|
+
def test_non_bzipped
|
243
|
+
Bzip2::FFI::Reader.open(fixture_path('lorem.txt')) do |reader|
|
244
|
+
assert_raises(Bzip2::FFI::Error::MagicDataError) { reader.read }
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
def test_truncated_bzip
|
249
|
+
[1024, Bzip2::FFI::Reader::READ_BUFFER_SIZE, 8192].each do |size|
|
250
|
+
partial = StringIO.new
|
251
|
+
|
252
|
+
File.open(fixture_path('bzipped'), 'rb') do |input|
|
253
|
+
buffer = input.read(size)
|
254
|
+
refute_nil(buffer)
|
255
|
+
assert_equal(size, buffer.bytesize)
|
256
|
+
partial.write(buffer)
|
257
|
+
end
|
258
|
+
|
259
|
+
partial.seek(0)
|
260
|
+
|
261
|
+
Bzip2::FFI::Reader.open(partial) do |reader|
|
262
|
+
assert_raises(Bzip2::FFI::Error::UnexpectedEofError) { reader.read }
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
def test_corrupted_bzip
|
268
|
+
corrupted = StringIO.new
|
269
|
+
|
270
|
+
File.open(fixture_path('bzipped'), 'rb') do |file|
|
271
|
+
corrupted.write(file.read)
|
272
|
+
end
|
273
|
+
|
274
|
+
corrupted.seek(4000)
|
275
|
+
corrupted.write("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0")
|
276
|
+
|
277
|
+
corrupted.seek(0)
|
278
|
+
|
279
|
+
Bzip2::FFI::Reader.open(corrupted) do |reader|
|
280
|
+
assert_raises(Bzip2::FFI::Error::DataError) { reader.read }
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
def test_data_after_compressed
|
285
|
+
suffixed = StringIO.new
|
286
|
+
|
287
|
+
File.open(fixture_path('bzipped'), 'rb') do |file|
|
288
|
+
suffixed.write(file.read)
|
289
|
+
end
|
290
|
+
|
291
|
+
suffixed.write('Test')
|
292
|
+
|
293
|
+
suffixed.seek(0)
|
294
|
+
|
295
|
+
Bzip2::FFI::Reader.open(suffixed) do |reader|
|
296
|
+
assert_equal(65670, reader.read.bytesize)
|
297
|
+
assert_nil(reader.read(1))
|
298
|
+
assert_equal(0, reader.read.bytesize)
|
299
|
+
end
|
300
|
+
|
301
|
+
assert_equal('Test', suffixed.read)
|
302
|
+
end
|
303
|
+
|
304
|
+
def test_data_after_compressed_no_seek
|
305
|
+
suffixed = StringIO.new
|
306
|
+
|
307
|
+
File.open(fixture_path('bzipped'), 'rb') do |file|
|
308
|
+
suffixed.write(file.read)
|
309
|
+
end
|
310
|
+
|
311
|
+
suffixed.write('Test')
|
312
|
+
|
313
|
+
suffixed.seek(0)
|
314
|
+
|
315
|
+
class << suffixed
|
316
|
+
undef_method :seek
|
317
|
+
end
|
318
|
+
|
319
|
+
Bzip2::FFI::Reader.open(suffixed) do |reader|
|
320
|
+
assert_equal(65670, reader.read.bytesize)
|
321
|
+
assert_nil(reader.read(1))
|
322
|
+
assert_equal(0, reader.read.bytesize)
|
323
|
+
end
|
324
|
+
|
325
|
+
# For this input, the suffix will already have been consumed before the
|
326
|
+
# end of the bzip2 stream is reached. There is no seek method, so it is not
|
327
|
+
# possible to restore the position to the end of the bzip2 stream.
|
328
|
+
assert_equal(0, suffixed.read.bytesize)
|
329
|
+
end
|
330
|
+
|
331
|
+
def test_data_after_compressed_seek_raises_io_error
|
332
|
+
suffixed = StringIO.new
|
333
|
+
|
334
|
+
File.open(fixture_path('bzipped'), 'rb') do |file|
|
335
|
+
suffixed.write(file.read)
|
336
|
+
end
|
337
|
+
|
338
|
+
suffixed.write('Test')
|
339
|
+
|
340
|
+
suffixed.seek(0)
|
341
|
+
|
342
|
+
def suffixed.seek(amount, whence = IO::SEEK_SET)
|
343
|
+
raise IOError, 'Cannot seek'
|
344
|
+
end
|
345
|
+
|
346
|
+
Bzip2::FFI::Reader.open(suffixed) do |reader|
|
347
|
+
assert_equal(65670, reader.read.bytesize)
|
348
|
+
assert_nil(reader.read(1))
|
349
|
+
assert_equal(0, reader.read.bytesize)
|
350
|
+
end
|
351
|
+
|
352
|
+
# For this input, the suffix will already have been consumed before the
|
353
|
+
# end of the bzip2 stream is reached. There is no seek method, so it is not
|
354
|
+
# possible to restore the position to the end of the bzip2 stream.
|
355
|
+
assert_equal(0, suffixed.read.bytesize)
|
356
|
+
end
|
357
|
+
|
358
|
+
def test_finalizer
|
359
|
+
# Code coverage will verify that the finalizer was called.
|
360
|
+
10.times { Bzip2::FFI::Reader.new(StringIO.new) }
|
361
|
+
GC.start
|
362
|
+
end
|
363
|
+
|
364
|
+
def test_open_io_nil
|
365
|
+
assert_raises(ArgumentError) { Bzip2::FFI::Reader.open(nil) }
|
366
|
+
end
|
367
|
+
|
368
|
+
def test_open_io_with_no_read_method
|
369
|
+
assert_raises(ArgumentError) { Bzip2::FFI::Reader.open(Object.new) }
|
370
|
+
end
|
371
|
+
|
372
|
+
def test_open_block_io
|
373
|
+
io = StringIO.new
|
374
|
+
Bzip2::FFI::Reader.open(io, autoclose: true) do |reader|
|
375
|
+
assert_same(io, reader.send(:io))
|
376
|
+
assert_equal(true, reader.autoclose?)
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
def test_open_no_block_io
|
381
|
+
io = StringIO.new
|
382
|
+
reader = Bzip2::FFI::Reader.open(io, autoclose: true)
|
383
|
+
begin
|
384
|
+
assert_same(io, reader.send(:io))
|
385
|
+
assert_equal(true, reader.autoclose?)
|
386
|
+
ensure
|
387
|
+
reader.close
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
def test_open_block_path
|
392
|
+
path = fixture_path('bzipped')
|
393
|
+
[path, Pathname.new(path)].each do |path_param|
|
394
|
+
Bzip2::FFI::Reader.open(path_param) do |reader|
|
395
|
+
io = reader.send(:io)
|
396
|
+
assert_kind_of(File, io)
|
397
|
+
assert_equal(path, io.path)
|
398
|
+
assert_raises(IOError) { io.write('test') }
|
399
|
+
assert_nothing_raised { io.read(1) }
|
400
|
+
end
|
401
|
+
end
|
402
|
+
end
|
403
|
+
|
404
|
+
def test_open_no_block_path
|
405
|
+
path = fixture_path('bzipped')
|
406
|
+
[path, Pathname.new(path)].each do |path_param|
|
407
|
+
reader = Bzip2::FFI::Reader.open(path_param)
|
408
|
+
begin
|
409
|
+
io = reader.send(:io)
|
410
|
+
assert_kind_of(File, io)
|
411
|
+
assert_equal(path, io.path)
|
412
|
+
assert_raises(IOError) { io.write('test') }
|
413
|
+
assert_nothing_raised { io.read(1) }
|
414
|
+
ensure
|
415
|
+
io.close
|
416
|
+
end
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
def test_open_block_path_always_autoclosed
|
421
|
+
Bzip2::FFI::Reader.open(fixture_path('bzipped'), autoclose: false) do |reader|
|
422
|
+
assert_equal(true, reader.autoclose?)
|
423
|
+
end
|
424
|
+
end
|
425
|
+
|
426
|
+
def test_open_no_block_path_always_autoclosed
|
427
|
+
reader = Bzip2::FFI::Reader.open(fixture_path('bzipped'), autoclose: false)
|
428
|
+
begin
|
429
|
+
assert_equal(true, reader.autoclose?)
|
430
|
+
ensure
|
431
|
+
reader.close
|
432
|
+
end
|
433
|
+
end
|
434
|
+
|
435
|
+
def test_open_path_does_not_exist
|
436
|
+
Dir.mktmpdir('bzip2-ffi-test') do |dir|
|
437
|
+
assert_raises(Errno::ENOENT) { Bzip2::FFI::Reader.open(File.join(dir, 'test')) }
|
438
|
+
end
|
439
|
+
end
|
440
|
+
|
441
|
+
def test_open_proc_not_allowed
|
442
|
+
assert_raises(ArgumentError) { Bzip2::FFI::Reader.open(-> { StringIO.new }) }
|
443
|
+
end
|
444
|
+
|
445
|
+
def test_open_after_open_file_exception_closes_file
|
446
|
+
Bzip2::FFI::Reader.test_after_open_file_raise_exception = true
|
447
|
+
assert_raises(RuntimeError) { Bzip2::FFI::Reader.open(fixture_path('bzipped')) }
|
448
|
+
file = Bzip2::FFI::Reader.test_after_open_file_last_io
|
449
|
+
refute_nil(file)
|
450
|
+
assert(file.closed?)
|
451
|
+
end
|
452
|
+
|
453
|
+
def test_class_read_initialize_nil_io
|
454
|
+
assert_raises(ArgumentError) { Bzip2::FFI::Reader.read(nil) }
|
455
|
+
end
|
456
|
+
|
457
|
+
def test_class_read_io_with_no_read_method
|
458
|
+
assert_raises(ArgumentError) { Bzip2::FFI::Reader.read(Object.new) }
|
459
|
+
end
|
460
|
+
|
461
|
+
def class_read_test(content)
|
462
|
+
Dir.mktmpdir('bzip2-ffi-test') do |dir|
|
463
|
+
uncompressed = File.join(dir, 'test')
|
464
|
+
File.write(uncompressed, content)
|
465
|
+
assert_bzip2_successful(uncompressed)
|
466
|
+
compressed = File.join(dir, 'test.bz2')
|
467
|
+
result = yield compressed
|
468
|
+
assert_equal(content, result)
|
469
|
+
assert_same(Encoding::ASCII_8BIT, result.encoding)
|
470
|
+
end
|
471
|
+
end
|
472
|
+
|
473
|
+
def test_class_read_io
|
474
|
+
class_read_test('test_io') do |compressed|
|
475
|
+
File.open(compressed, 'rb') do |file|
|
476
|
+
Bzip2::FFI::Reader.read(file, {})
|
477
|
+
end
|
478
|
+
end
|
479
|
+
end
|
480
|
+
|
481
|
+
def test_class_read_path
|
482
|
+
class_read_test('test_path') do |compressed|
|
483
|
+
Bzip2::FFI::Reader.read(compressed)
|
484
|
+
end
|
485
|
+
end
|
486
|
+
|
487
|
+
def test_class_read_pathname
|
488
|
+
class_read_test('test_pathname') do |compressed|
|
489
|
+
Bzip2::FFI::Reader.read(Pathname.new(compressed))
|
490
|
+
end
|
491
|
+
end
|
492
|
+
|
493
|
+
def test_class_read_path_file_does_not_exist
|
494
|
+
Dir.mktmpdir('bzip2-ffi-test') do |dir|
|
495
|
+
assert_raises(Errno::ENOENT) { Bzip2::FFI::Reader.read(File.join(dir, 'test')) }
|
496
|
+
end
|
497
|
+
end
|
498
|
+
end
|