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,98 @@
1
+ unless RUBY_ENGINE == 'jruby'
2
+ require 'simplecov'
3
+ require 'coveralls'
4
+
5
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
6
+ SimpleCov::Formatter::HTMLFormatter,
7
+ Coveralls::SimpleCov::Formatter
8
+ ]
9
+
10
+ SimpleCov.start do
11
+ add_filter 'test'
12
+ project_name 'Bzip2::FFI'
13
+ end
14
+ end
15
+
16
+ require 'bzip2/ffi'
17
+ require 'fileutils'
18
+ require 'minitest/autorun'
19
+ require 'open3'
20
+
21
+ class Bzip2::FFI::IO
22
+ class << self
23
+ attr_accessor :test_after_open_file_raise_exception
24
+ attr_accessor :test_after_open_file_last_io
25
+
26
+ private
27
+
28
+ alias_method :default_after_open_file, :after_open_file
29
+
30
+ def after_open_file(io)
31
+ @test_after_open_file_last_io = io
32
+ default_after_open_file(io)
33
+ raise 'test' if test_after_open_file_raise_exception
34
+ end
35
+ end
36
+ end
37
+
38
+ module TestHelper
39
+ BASE_DIR = File.expand_path(File.dirname(__FILE__))
40
+
41
+ module Assertions
42
+ def assert_files_identical(exp, act, msg = nil)
43
+ msg = message(msg) { "Expected file #{act} to be identical to #{exp}" }
44
+ assert(FileUtils.identical?(exp, act), msg)
45
+ end
46
+
47
+ def assert_bzip2_successful(file)
48
+ assert_bzip2_command_successful(path_separators_for_command(file))
49
+ end
50
+
51
+ def assert_bunzip2_successful(file)
52
+ assert_bzip2_command_successful('--decompress', path_separators_for_command(file))
53
+ end
54
+
55
+ def assert_nothing_raised(msg = nil)
56
+ begin
57
+ yield
58
+ rescue => e
59
+ full_message = message(msg) { exception_details(e, 'Exception raised: ') }
60
+ flunk(full_message)
61
+ end
62
+ end
63
+
64
+ private
65
+
66
+ if File::ALT_SEPARATOR
67
+ def path_separators_for_command(path)
68
+ path.gsub(File::SEPARATOR, File::ALT_SEPARATOR)
69
+ end
70
+ else
71
+ def path_separators_for_command(path)
72
+ path
73
+ end
74
+ end
75
+
76
+ def assert_bzip2_command_successful(*arguments)
77
+ out, err, status = Open3.capture3(*(['bzip2'] + arguments))
78
+
79
+ args_string = arguments.collect {|a| "'#{a}'" }.join(' ')
80
+ assert(err == '', "`bzip2 #{args_string}` returned error: #{err}")
81
+ assert(out == '', "`bzip2 #{args_string}` returned output: #{out}")
82
+ assert(status.exitstatus == 0, "`bzip2 #{args_string}` exit status was non-zero")
83
+ end
84
+ end
85
+
86
+ module Fixtures
87
+ FIXTURES_DIR = File.join(BASE_DIR, 'fixtures')
88
+
89
+ def fixture_path(fixture)
90
+ File.join(FIXTURES_DIR, fixture)
91
+ end
92
+ end
93
+ end
94
+
95
+ class Minitest::Test
96
+ include TestHelper::Assertions
97
+ include TestHelper::Fixtures
98
+ end
@@ -0,0 +1,7 @@
1
+ require 'test_helper'
2
+
3
+ class VersionTest < Minitest::Test
4
+ def test_version
5
+ assert(Bzip2::FFI::VERSION =~ /\A\d+(\.\d+){2}\z/)
6
+ end
7
+ end
@@ -0,0 +1,439 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'pathname'
4
+ require 'test_helper'
5
+ require 'tmpdir'
6
+
7
+ class WriterTest < Minitest::Test
8
+ class DummyIO
9
+ attr_reader :written_bytes
10
+
11
+ def initialize
12
+ @written_bytes = 0
13
+ end
14
+
15
+ def write(string)
16
+ @written_bytes += string.bytesize
17
+ end
18
+ end
19
+
20
+ def setup
21
+ Bzip2::FFI::Writer.test_after_open_file_raise_exception = false
22
+ end
23
+
24
+ def teardown
25
+ Bzip2::FFI::Writer.test_after_open_file_raise_exception = false
26
+ Bzip2::FFI::Writer.test_after_open_file_last_io = nil
27
+ end
28
+
29
+ def write_io(writer, io, read_size = nil)
30
+ if read_size
31
+ loop do
32
+ buffer = io.read(read_size)
33
+ break unless buffer
34
+ assert_equal(buffer.bytesize, writer.write(buffer))
35
+ end
36
+ else
37
+ buffer = io.read
38
+ assert_equal(buffer.bytesize, writer.write(buffer))
39
+ end
40
+ end
41
+
42
+ def write_fixture(writer, fixture, read_size = nil)
43
+ File.open(fixture_path(fixture), 'rb') do |input|
44
+ write_io(writer, input, read_size)
45
+ end
46
+ end
47
+
48
+ def bunzip_and_compare(compressed, fixture_or_strings)
49
+ assert_bunzip2_successful(compressed)
50
+
51
+ uncompressed = compressed.chomp('.bz2')
52
+ assert(File.exist?(uncompressed))
53
+
54
+ if fixture_or_strings
55
+ if fixture_or_strings.kind_of?(Array)
56
+ File.open(uncompressed, 'rb') do |file|
57
+ fixture_or_strings.each do |string|
58
+ string = string.to_s
59
+ buffer = file.read(string.bytesize)
60
+ refute_nil(buffer)
61
+ assert_equal(string.bytesize, buffer.bytesize)
62
+ assert_equal(string.bytes.to_a, buffer.bytes.to_a)
63
+ end
64
+
65
+ assert_nil(file.read(1))
66
+ end
67
+ else
68
+ assert_files_identical(fixture_path(fixture_or_strings), uncompressed)
69
+ end
70
+ else
71
+ assert_equal(0, File.size(uncompressed))
72
+ end
73
+ end
74
+
75
+ def bunzip_test(fixture_or_strings, options = {})
76
+ Dir.mktmpdir('bzip2-ffi-test') do |dir|
77
+ compressed = File.join(dir, "test.bz2")
78
+ Bzip2::FFI::Writer.open(compressed, options[:writer_options] || {}) do |writer|
79
+ if fixture_or_strings
80
+ if fixture_or_strings.kind_of?(Array)
81
+ fixture_or_strings.each do |string|
82
+ assert_equal(string.to_s.bytesize, writer.write(string))
83
+ end
84
+ else
85
+ write_fixture(writer, fixture_or_strings, options[:read_size])
86
+ end
87
+ end
88
+ end
89
+
90
+ bunzip_and_compare(compressed, fixture_or_strings)
91
+ end
92
+ end
93
+
94
+ def test_initialize_nil_io
95
+ assert_raises(ArgumentError) { Bzip2::FFI::Writer.new(nil) }
96
+ end
97
+
98
+ def test_initialize_io_with_no_write_method
99
+ assert_raises(ArgumentError) { Bzip2::FFI::Writer.new(Object.new) }
100
+ end
101
+
102
+ def test_initialize_invalid_block_size
103
+ assert_raises(RangeError) { Bzip2::FFI::Writer.new(DummyIO.new, block_size: 0) }
104
+ assert_raises(RangeError) { Bzip2::FFI::Writer.new(DummyIO.new, block_size: 10) }
105
+ end
106
+
107
+ def test_initialize_invalid_work_factor
108
+ assert_raises(RangeError) { Bzip2::FFI::Writer.new(DummyIO.new, work_factor: -1) }
109
+ assert_raises(RangeError) { Bzip2::FFI::Writer.new(DummyIO.new, work_factor: 251) }
110
+ end
111
+
112
+ def test_no_write
113
+ bunzip_test(nil)
114
+ end
115
+
116
+ def test_fixture_text
117
+ [16, 1024, 16384, nil].each do |read_size|
118
+ bunzip_test('lorem.txt', read_size: read_size)
119
+ end
120
+ end
121
+
122
+ def test_fixture_very_compressible
123
+ [16, 1024, 16384, nil].each do |read_size|
124
+ bunzip_test('zero.txt', read_size: read_size)
125
+ end
126
+ end
127
+
128
+ def test_fixture_uncompressible
129
+ [16, 1024, 16384, nil].each do |read_size|
130
+ bunzip_test('bzipped', read_size: read_size)
131
+ end
132
+ end
133
+
134
+ def test_fixture_image
135
+ [16, 1024, 16384, nil].each do |read_size|
136
+ bunzip_test('moon.tiff', read_size: read_size)
137
+ end
138
+ end
139
+
140
+ def test_encoding_handling
141
+ bunzip_test(['áÁçÇðÐéÉ'.encode(Encoding::UTF_8), 'áÁçÇðÐéÉ'.encode(Encoding::ISO_8859_1)])
142
+ end
143
+
144
+ def test_write_non_string
145
+ bunzip_test([:test, 42])
146
+ end
147
+
148
+ def test_block_size
149
+ sizes = [1, 9].collect do |block_size|
150
+ io = DummyIO.new
151
+
152
+ Bzip2::FFI::Writer.open(io, block_size: block_size) do |writer|
153
+ write_fixture(writer, 'lorem.txt')
154
+ end
155
+
156
+ io.written_bytes
157
+ end
158
+
159
+ assert(sizes.last < sizes.first, 'compressed size with block_size = 1 is not less than compressed size with block_size = 9')
160
+ end
161
+
162
+ def test_default_block_size
163
+ # The default block size should be 9. Check that the size of the compressed
164
+ # stream for the default block size is the same as the size when compressed
165
+ # with :block_size set to 9.
166
+
167
+ explicit_io = DummyIO.new
168
+ Bzip2::FFI::Writer.open(explicit_io, block_size: 9) do |writer|
169
+ write_fixture(writer, 'lorem.txt')
170
+ end
171
+
172
+ default_io = DummyIO.new
173
+ Bzip2::FFI::Writer.open(default_io) do |writer|
174
+ write_fixture(writer, 'lorem.txt')
175
+ end
176
+
177
+ assert_equal(explicit_io.written_bytes, default_io.written_bytes)
178
+ end
179
+
180
+ def test_work_factor
181
+ # Not trivial to check if the value passed has any effect. Just check that
182
+ # there are no failures for values within the acceptable range.
183
+
184
+ [0, 100, 250].each do |work_factor|
185
+ bunzip_test('lorem.txt', writer_options: {work_factor: work_factor})
186
+ end
187
+ end
188
+
189
+ def test_write_after_close
190
+ writer = Bzip2::FFI::Writer.new(DummyIO.new)
191
+ writer.close
192
+ assert_raises(IOError) { writer.write('test') }
193
+ end
194
+
195
+ def test_flush
196
+ non_flushed = DummyIO.new
197
+ flushed = DummyIO.new
198
+
199
+ Bzip2::FFI::Writer.open(non_flushed) do |writer|
200
+ write_fixture(writer, 'lorem.txt', 4096)
201
+ end
202
+
203
+ Bzip2::FFI::Writer.open(flushed) do |writer|
204
+ File.open(fixture_path('lorem.txt'), 'rb') do |fixture|
205
+ 5.times do
206
+ buffer = fixture.read(4096)
207
+ assert_equal(4096, buffer.bytesize)
208
+ assert_equal(4096, writer.write(buffer))
209
+ end
210
+
211
+ assert_same(writer, writer.flush)
212
+
213
+ write_io(writer, fixture, 4096)
214
+ end
215
+ end
216
+
217
+ # Flushed stream will be larger because it forces libbz2 to terminate the
218
+ # current compression block earlier that it would otherwise do.
219
+ assert(flushed.written_bytes > non_flushed.written_bytes, 'flushed Writer did not create a larger output')
220
+ end
221
+
222
+ def test_flush_after_close
223
+ writer = Bzip2::FFI::Writer.new(DummyIO.new)
224
+ writer.close
225
+ assert_raises(IOError) { writer.flush }
226
+ end
227
+
228
+ def test_close_returns_nil
229
+ writer = Bzip2::FFI::Writer.new(DummyIO.new)
230
+ assert_nil(writer.close)
231
+ end
232
+
233
+ def test_finalizer
234
+ # Code coverage will verify that the finalizer was called.
235
+ 10.times { Bzip2::FFI::Writer.new(DummyIO.new) }
236
+ GC.start
237
+ end
238
+
239
+ def test_open_io_nil
240
+ assert_raises(ArgumentError) { Bzip2::FFI::Writer.open(nil) }
241
+ end
242
+
243
+ def test_open_io_with_no_write_method
244
+ assert_raises(ArgumentError) { Bzip2::FFI::Writer.open(Object.new) }
245
+ end
246
+
247
+ def test_open_invalid_block_size
248
+ assert_raises(RangeError) { Bzip2::FFI::Writer.open(DummyIO.new, block_size: 0) }
249
+ assert_raises(RangeError) { Bzip2::FFI::Writer.open(DummyIO.new, block_size: 10) }
250
+ end
251
+
252
+ def test_open_invalid_work_factor
253
+ assert_raises(RangeError) { Bzip2::FFI::Writer.open(DummyIO.new, work_factor: -1) }
254
+ assert_raises(RangeError) { Bzip2::FFI::Writer.open(DummyIO.new, work_factor: 251) }
255
+ end
256
+
257
+ def test_open_block_io
258
+ io = DummyIO.new
259
+ Bzip2::FFI::Writer.open(io, autoclose: true) do |writer|
260
+ assert_same(io, writer.send(:io))
261
+ assert_equal(true, writer.autoclose?)
262
+ end
263
+ end
264
+
265
+ def test_open_no_block_io
266
+ io = DummyIO.new
267
+ writer = Bzip2::FFI::Writer.open(io, autoclose: true)
268
+ begin
269
+ assert_same(io, writer.send(:io))
270
+ assert_equal(true, writer.autoclose?)
271
+ ensure
272
+ writer.close
273
+ end
274
+ end
275
+
276
+ def test_open_block_path
277
+ Dir.mktmpdir('bzip2-ffi-test') do |dir|
278
+ path = File.join(dir, 'test')
279
+ [path, Pathname.new(path)].each do |path_param|
280
+ Bzip2::FFI::Writer.open(path_param) do |writer|
281
+ io = writer.send(:io)
282
+ assert_kind_of(File, io)
283
+ assert_equal(path, io.path)
284
+ assert_raises(IOError) { io.read(1) }
285
+ assert_nothing_raised { io.write('test') }
286
+ end
287
+ end
288
+ end
289
+ end
290
+
291
+ def test_open_no_block_path
292
+ Dir.mktmpdir('bzip2-ffi-test') do |dir|
293
+ path = File.join(dir, 'test')
294
+ [path, Pathname.new(path)].each do |path_param|
295
+ writer = Bzip2::FFI::Writer.open(path_param)
296
+ begin
297
+ io = writer.send(:io)
298
+ assert_kind_of(File, io)
299
+ assert_equal(path, io.path)
300
+ assert_raises(IOError) { io.read(1) }
301
+ assert_nothing_raised { io.write('test') }
302
+ ensure
303
+ writer.close
304
+ end
305
+ end
306
+ end
307
+ end
308
+
309
+ def test_open_block_path_always_autoclosed
310
+ Dir.mktmpdir('bzip2-ffi-test') do |dir|
311
+ Bzip2::FFI::Writer.open(File.join(dir, 'test'), autoclose: false) do |writer|
312
+ assert_equal(true, writer.autoclose?)
313
+ end
314
+ end
315
+ end
316
+
317
+ def test_open_no_block_path_always_autoclosed
318
+ Dir.mktmpdir('bzip2-ffi-test') do |dir|
319
+ writer = Bzip2::FFI::Writer.open(File.join(dir, 'test'), autoclose: false)
320
+ begin
321
+ assert_equal(true, writer.autoclose?)
322
+ ensure
323
+ writer.close
324
+ end
325
+ end
326
+ end
327
+
328
+ def test_open_parent_dir_does_not_exist
329
+ Dir.mktmpdir('bzip2-ffi-test') do |dir|
330
+ assert_raises(Errno::ENOENT) { Bzip2::FFI::Writer.open(File.join(dir, 'test_dir', 'test_file')) }
331
+ end
332
+ end
333
+
334
+ def test_open_existing_file_truncated
335
+ plain_content = 'This is not a bzip'
336
+ compressed_content = 'This is a bzip'
337
+
338
+ Dir.mktmpdir('bzip2-ffi-test') do |dir|
339
+ path = File.join(dir, 'test.bz2')
340
+
341
+ File.write(path, 'This is not a bzip')
342
+
343
+ File.open(path, 'rb') do |file|
344
+ assert_equal(plain_content, file.read(plain_content.bytesize))
345
+ end
346
+
347
+ Bzip2::FFI::Writer.open(path) do |writer|
348
+ writer.write(compressed_content)
349
+ end
350
+
351
+ File.open(path, 'rb') do |file|
352
+ refute_equal(plain_content, file.read(plain_content.bytesize))
353
+ end
354
+
355
+ bunzip_and_compare(path, [compressed_content])
356
+ end
357
+ end
358
+
359
+ def test_open_proc_not_allowed
360
+ assert_raises(ArgumentError) { Bzip2::FFI::Writer.open(-> { StringIO.new }) }
361
+ end
362
+
363
+ def test_open_after_open_file_exception_closes_file
364
+ Dir.mktmpdir('bzip2-ffi-test') do |dir|
365
+ Bzip2::FFI::Writer.test_after_open_file_raise_exception = true
366
+ assert_raises(RuntimeError) { Bzip2::FFI::Writer.open(File.join(dir, 'test')) }
367
+ file = Bzip2::FFI::Writer.test_after_open_file_last_io
368
+ refute_nil(file)
369
+ assert(file.closed?)
370
+ end
371
+ end
372
+
373
+ def test_class_write_nil_io
374
+ assert_raises(ArgumentError) { Bzip2::FFI::Writer.write(nil, 'test') }
375
+ end
376
+
377
+ def test_class_write_io_with_no_write_method
378
+ assert_raises(ArgumentError) { Bzip2::FFI::Writer.write(Object.new, 'test') }
379
+ end
380
+
381
+ def test_class_write_invalid_block_size
382
+ assert_raises(RangeError) { Bzip2::FFI::Writer.write(DummyIO.new, 'test', block_size: 0) }
383
+ assert_raises(RangeError) { Bzip2::FFI::Writer.write(DummyIO.new, 'test', block_size: 10) }
384
+ end
385
+
386
+ def test_class_write_invalid_work_factor
387
+ assert_raises(RangeError) { Bzip2::FFI::Writer.write(DummyIO.new, 'test', work_factor: -1) }
388
+ assert_raises(RangeError) { Bzip2::FFI::Writer.write(DummyIO.new, 'test', work_factor: 251) }
389
+ end
390
+
391
+ def class_write_test(content)
392
+ Dir.mktmpdir('bzip2-ffi-test') do |dir|
393
+ compressed = File.join(dir, 'test.bz2')
394
+ result = yield compressed, content
395
+ assert_equal(content.bytesize, result)
396
+ bunzip_and_compare(compressed, [content])
397
+ end
398
+ end
399
+
400
+ def test_class_write_io
401
+ class_write_test('test_io') do |compressed, content|
402
+ File.open(compressed, 'wb') do |file|
403
+ Bzip2::FFI::Writer.write(file, content)
404
+ end
405
+ end
406
+ end
407
+
408
+ def test_class_write_path
409
+ class_write_test('test_path') do |compressed, content|
410
+ Bzip2::FFI::Writer.write(compressed, content)
411
+ end
412
+ end
413
+
414
+ def test_class_write_pathname
415
+ class_write_test('test_pathname') do |compressed, content|
416
+ Bzip2::FFI::Writer.write(Pathname.new(compressed), content)
417
+ end
418
+ end
419
+
420
+ def test_class_write_path_not_exist
421
+ Dir.mktmpdir('bzip2-ffi-test') do |dir|
422
+ assert_raises(Errno::ENOENT) { Bzip2::FFI::Writer.write(File.join(dir, 'test_dir', 'test_file'), 'test') }
423
+ end
424
+ end
425
+
426
+ def test_class_write_existing_file_truncated
427
+ plain_content = 'This is not a bzip'
428
+ compressed_content = 'This is a bzip'
429
+
430
+ Dir.mktmpdir('bzip2-ffi-test') do |dir|
431
+ path = File.join(dir, 'test.bz2')
432
+ File.write(path, 'This is not a bzip')
433
+ assert_equal(plain_content, File.read(path, plain_content.bytesize))
434
+ Bzip2::FFI::Writer.write(path, compressed_content)
435
+ refute_equal(plain_content, File.read(path, plain_content.bytesize))
436
+ bunzip_and_compare(path, [compressed_content])
437
+ end
438
+ end
439
+ end