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.
@@ -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
@@ -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