bzip2-ffi 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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